diff --git a/.gitignore b/.gitignore index 85f24f6..b216b54 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ # Carthage # # Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts + Carthage/Checkouts Carthage/Build diff --git a/Cartfile b/Cartfile index ea5eec7..2d16cee 100644 --- a/Cartfile +++ b/Cartfile @@ -1,3 +1,4 @@ -github "tealium/tealium-swift" ~> 1.9 -binary "https://raw.githubusercontent.com/AppsFlyerSDK/AppsFlyerFramework/master/AppsFlyerLib.json" ~> 5.2 +github "tealium/tealium-swift" ~> 2.1 +binary "https://raw.githubusercontent.com/AppsFlyerSDK/AppsFlyerFramework/master/Carthage/appsflyer-ios.json" ~> 6.0 + diff --git a/Cartfile.resolved b/Cartfile.resolved index 45f305b..e1c3f99 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,3 +1,2 @@ -binary "https://raw.githubusercontent.com/AppsFlyerSDK/AppsFlyerFramework/master/AppsFlyerLib.json" "5.2.0" -binary "https://tags.tiqcdn.com/dle/tealiummobile/tealium-ios-carthage/tealium-carthage-plcrashreporter.json?_cb=2" "1.4.0" -github "tealium/tealium-swift" "1.9.4" +binary "https://raw.githubusercontent.com/AppsFlyerSDK/AppsFlyerFramework/master/Carthage/appsflyer-ios.json" "6.0.3" +git "file:///Users/christina/Projects/work-repos/github/tealium-swift-builder" "9b5aa0cbb257718b98acb769589fcd7d56cdfd51" diff --git a/Objective-C/AppsFlyerCommandTracker.swift b/Objective-C/AppsFlyerCommandTracker.swift deleted file mode 100644 index 8c52243..0000000 --- a/Objective-C/AppsFlyerCommandTracker.swift +++ /dev/null @@ -1,184 +0,0 @@ -// -// AppsFlyerCommandTracker.swift -// AppsFlyerRemoteCommand -// -// Created by Christina Sund on 5/29/19. -// Copyright © 2019 Christina. All rights reserved. -// - -import Foundation -import AppsFlyerLib -import TealiumIOS - -@objc -public protocol AppsFlyerTrackable { - func initialize(appId: String, appDevKey: String) - func initialize(appId: String, appDevKey: String, config: [String: Any]) - func trackLaunch() - func trackEvent(_ eventName: String, values: [String: Any]) - func trackLocation(longitude: Double, latitude: Double) - func setHost(_ host: String, with prefix: String) - func setUserEmails(emails: [String], with cryptType: Int) - func currencyCode(_ currency: String) - func customerId(_ id: String) - func disableTracking(_ disable: Bool) - func resolveDeepLinkURLs(_ urls: [String]) -} - -@objc -public class AppsFlyerCommandTracker: NSObject, AppsFlyerTrackable, TealiumRegistration { - - weak var tealium: Tealium? - - @objc - public override init() { } - - @objc - public init(tealium: Tealium) { - super.init() - self.tealium = tealium - AppsFlyerTracker.shared().delegate = self - } - - public func initialize(appId: String, appDevKey: String) { - AppsFlyerTracker.shared().appsFlyerDevKey = appDevKey - AppsFlyerTracker.shared().appleAppID = appId - } - - public func initialize(appId: String, appDevKey: String, config: [String: Any]) { - AppsFlyerTracker.shared().appsFlyerDevKey = appDevKey - AppsFlyerTracker.shared().appleAppID = appId - if let debug = config[AppsFlyerConstants.Configuration.debug] as? Bool { - AppsFlyerTracker.shared().isDebug = debug - } - if let disableAdTracking = config[AppsFlyerConstants.Configuration.disableAdTracking] as? Bool { - AppsFlyerTracker.shared().disableIAdTracking = disableAdTracking - } - if let disableAppleAdTracking = config[AppsFlyerConstants.Configuration.disableAppleAdTracking] as? Bool { - AppsFlyerTracker.shared().disableAppleAdSupportTracking = disableAppleAdTracking - } - if let minTimeBetweenSessions = config[AppsFlyerConstants.Configuration.minTimeBetweenSessions] as? Int { - AppsFlyerTracker.shared().minTimeBetweenSessions = UInt(minTimeBetweenSessions) - } - if let anonymizeUser = config[AppsFlyerConstants.Configuration.anonymizeUser] as? Bool { - AppsFlyerTracker.shared().deviceTrackingDisabled = anonymizeUser - } - if let shouldCollectDeviceName = config[AppsFlyerConstants.Configuration.collectDeviceName] as? Bool { - AppsFlyerTracker.shared().shouldCollectDeviceName = shouldCollectDeviceName - } - if let customData = config[AppsFlyerConstants.Configuration.customData] as? [AnyHashable: Any] { - AppsFlyerTracker.shared().customData = customData - } - } - - public func trackLaunch() { - AppsFlyerTracker.shared().trackAppLaunch() - } - - public func trackEvent(_ eventName: String, values: [String: Any]) { - AppsFlyerTracker.shared().trackEvent(eventName, withValues: values) - } - - public func trackLocation(longitude: Double, latitude: Double) { - AppsFlyerTracker.shared().trackLocation(longitude, latitude: latitude) - } - - /// Used to track push notification activity from native APNs or other push service - /// Please refer to this for more information: - /// https://support.appsflyer.com/hc/en-us/articles/207364076-Measuring-Push-Notification-Re-Engagement-Campaigns - public func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { - AppsFlyerTracker.shared().handlePushNotification(userInfo) - AppsFlyerTracker.shared().trackEvent(AppsFlyerConstants.Events.pushNotificationOpened, withValues: [:]) - } - - public func handlePushNofification(payload: [String: Any]?) { - AppsFlyerTracker.shared().handlePushNotification(payload) - } - - public func setHost(_ host: String, with prefix: String) { - AppsFlyerTracker.shared().setHost(host, withHostPrefix: prefix) - } - - public func setUserEmails(emails: [String], with cryptType: Int) { - AppsFlyerTracker.shared().setUserEmails(emails, with: EmailCryptType(rawValue: EmailCryptType.RawValue(cryptType))) - } - - public func currencyCode(_ currency: String) { - AppsFlyerTracker.shared().currencyCode = currency - } - - public func customerId(_ id: String) { - AppsFlyerTracker.shared().customerUserID = id - } - - public func disableTracking(_ disable: Bool) { - AppsFlyerTracker.shared().isStopTracking = disable - } - - /// APNs and Push Messaging must be configured in order to track installs. - /// Apple will not register the uninstall until 8 days after the user removes the app. - /// Instructions to set up: https://support.appsflyer.com/hc/en-us/articles/210289286-Uninstall-Measurement#iOS-Uninstall - public func registerPushToken(_ token: String) { - guard let dataToken = token.data(using: .utf8) else { return } - AppsFlyerTracker.shared().registerUninstall(dataToken) - } - - public func resolveDeepLinkURLs(_ urls: [String]) { - AppsFlyerTracker.shared().resolveDeepLinkURLs = urls - } - -} - -extension AppsFlyerCommandTracker: AppsFlyerTrackerDelegate { - - public func onConversionDataSuccess(_ conversionInfo: [AnyHashable: Any]) { - guard let tealium = tealium else { return } - guard let conversionInfo = conversionInfo as? [String: Any], - let firstLaunch = conversionInfo[AppsFlyerConstants.Attribution.firstLaunch] as? Bool else { - tealium.trackEvent(withTitle: AppsFlyerConstants.Attribution.conversionReceived, - dataSources: [:]) - return - } - guard firstLaunch else { - print("\(AppsFlyerConstants.attributionLog)Not First Launch") - return - } - tealium.trackEvent(withTitle: AppsFlyerConstants.Attribution.conversionReceived, - dataSources: conversionInfo) - - guard let status = conversionInfo[AppsFlyerConstants.Attribution.status] as? String else { - return - } - if (status == "Non-organic") { - if let mediaSource = conversionInfo[AppsFlyerConstants.Attribution.source], - let campaign = conversionInfo[AppsFlyerConstants.Attribution.campaign] { - print("\(AppsFlyerConstants.attributionLog)This is a Non-Organic install. Media source: \(mediaSource) Campaign: \(campaign)") - } - } else { - print("\(AppsFlyerConstants.attributionLog)This is an organic install.") - } - } - - public func onConversionDataFail(_ error: Error) { - tealium?.trackEvent(withTitle: AppsFlyerConstants.Attribution.error, - dataSources: [AppsFlyerConstants.Attribution.errorName: AppsFlyerConstants.Attribution.conversionFailure, - AppsFlyerConstants.Attribution.errorDescription: error.localizedDescription]) - } - - public func onAppOpenAttribution(_ attributionData: [AnyHashable: Any]) { - guard let tealium = self.tealium else { return } - guard let attributionData = attributionData as? [String: Any] else { - return tealium.trackEvent(withTitle: AppsFlyerConstants.Attribution.appOpen, - dataSources: [:]) - } - tealium.trackEvent(withTitle: AppsFlyerConstants.Attribution.appOpen, - dataSources: attributionData) - } - - public func onAppOpenAttributionFailure(_ error: Error) { - tealium?.trackEvent(withTitle: AppsFlyerConstants.Attribution.error, - dataSources: [AppsFlyerConstants.Attribution.errorName: AppsFlyerConstants.Attribution.appOpenFailure, - AppsFlyerConstants.Attribution.errorDescription: error.localizedDescription]) - } - -} diff --git a/Objective-C/AppsFlyerConstants.swift b/Objective-C/AppsFlyerConstants.swift deleted file mode 100644 index 541534a..0000000 --- a/Objective-C/AppsFlyerConstants.swift +++ /dev/null @@ -1,129 +0,0 @@ -// -// AppsFlyerConstants.swift -// TealiumAppsFlyer -// -// Created by Christina S on 5/29/19. -// Copyright © 2019 Tealium. All rights reserved. -// - -import Foundation - -public enum AppsFlyerConstants { - - static let commandName = "command_name" - static let separator: Character = "," - static let errorPrefix = "AppsFlyer Error: " - static let attributionLog = "AppsFlyer Attribution: " - - /// Standard AppsFlyer events: https://support.appsflyer.com/hc/en-us/articles/115005544169#Event-Types - public enum EventCommandNames: String, CaseIterable { - case achievelevel - case adclick - case adview - case addpaymentinfo - case addtocart - case addtowishlist - case completeregistration - case completetutorial - case viewedcontent - case search - case rate - case starttrial - case subscribe - case initiatecheckout - case purchase - case unlockachievement - case spentcredits - case listview - case travelbooking - case share - case invite - case reengage - case update - case login - case customersegment - } - - public enum CommandNames: String { - case launch = "launch" - case initialize = "initialize" - case trackLocation = "tracklocation" - case setHost = "sethost" - case setUserEmails = "setuseremails" - case setCurrencyCode = "setcurrencycode" - case setCustomerId = "setcustomerid" - case disableTracking = "disabletracking" - case resolveDeepLinkUrls = "resolvedeeplinkurls" - } - - public enum Configuration { - static let appId = "app_id" - static let appDevKey = "app_dev_key" - static let debug = "debug" - static let disableAdTracking = "disable_ad_tracking" - static let disableAppleAdTracking = "disable_apple_ad_tracking" - static let minTimeBetweenSessions = "time_between_sessions" - static let anonymizeUser = "anonymize_user" - static let collectDeviceName = "collect_device_name" - static let customData = "custom_data" - static let settings = "settings" - } - - public enum Parameters { - static let latitude = "af_lat" - static let longitude = "af_long" - static let pushPayload = "af_push_payload" - static let host = "host" - static let hostPrefix = "host_prefix" - static let emails = "customer_emails" - static let cryptType = "email_hash_type" - static let currency = "af_currency" - static let customerId = "af_customer_user_id" - static let stopTracking = "stop_tracking" - static let deepLinkUrls = "af_deep_link" - } - - public enum Events { - static let achievedLevel = "af_level_achieved" - static let addPaymentInfo = "af_add_payment_info" - static let addToCart = "af_add_to_cart" - static let addToWishlist = "af_add_to_wishlist" - static let completeRegistration = "af_complete_registration" - static let completeTutorial = "af_tutorial_completion" - static let initiateCheckout = "af_initiated_checkout" - static let purchase = "af_purchase" - static let subscribe = "af_subscribe" - static let startTrial = "af_start_trial" - static let rate = "af_rate" - static let search = "af_search" - static let spentCredits = "af_spent_credits" - static let unlockAchievement = "af_achievement_unlocked" - static let contentView = "af_content_view" - static let listView = "af_list_view" - static let adClick = "af_ad_click" - static let adView = "af_ad_view" - static let travelBooking = "af_travel_booking" - static let share = "af_share" - static let invite = "af_invite" - static let reEngage = "af_re_engage" - static let update = "af_update" - static let login = "af_login" - static let customerSegment = "af_customer_segment" - static let pushNotificationOpened = "af_opened_from_push_notification" - } - - public enum Attribution { - static let appOpen = "app_open_attribution" - static let appOpenFailure = "app_open_attribution_failure" - static let firstLaunch = "is_first_launch" - static let conversionReceived = "conversion_data_received" - static let conversionFailure = "conversion_data_failure" - static let errorName = "error_name" - static let errorDescription = "error_description" - static let status = "af_status" - static let source = "source" - static let campaign = "campaign" - static let error = "appsflyer_error" - } - -} diff --git a/Objective-C/AppsFlyerRemoteCommand.swift b/Objective-C/AppsFlyerRemoteCommand.swift deleted file mode 100644 index 3755fc0..0000000 --- a/Objective-C/AppsFlyerRemoteCommand.swift +++ /dev/null @@ -1,187 +0,0 @@ -// -// AppsFlyerRemoteCommand.swift -// AppsFlyerRemoteCommand -// -// Created by Christina Sund on 5/29/19. -// Copyright © 2019 Christina. All rights reserved. -// - -import Foundation -import TealiumIOS - -@objc -public class AppsFlyerRemoteCommand: NSObject { - - let appsFlyerCommandTracker: AppsFlyerTrackable - - @objc - public init(appsFlyerCommandTracker: AppsFlyerTrackable = AppsFlyerCommandTracker()) { - self.appsFlyerCommandTracker = appsFlyerCommandTracker - } - - @objc - public func remoteCommand() -> TEALRemoteCommandResponseBlock { - return { response in - guard var payload = response?.requestPayload as? [String: Any] else { - return - } - if let disableTracking = payload[AppsFlyerConstants.Parameters.stopTracking] as? Bool { - if disableTracking == true { - self.appsFlyerCommandTracker.disableTracking(true) - return - } - } - guard let command = payload[AppsFlyerConstants.commandName] as? String else { - return - } - let commands = command.split(separator: AppsFlyerConstants.separator) - let appsflyerCommands = commands.map { command in - return command.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) - } - payload = payload.filterVariables() - self.parseCommands(appsflyerCommands, payload: payload) - } - } - - public func parseCommands(_ commands: [String], payload: [String: Any]) { - commands.forEach { [weak self] command in - let commandName = AppsFlyerConstants.CommandNames(rawValue: command.lowercased()) - guard let self = self else { - return - } - switch commandName { - case .initialize: - guard let appId = payload[AppsFlyerConstants.Configuration.appId] as? String, - let appDevKey = payload[AppsFlyerConstants.Configuration.appDevKey] as? String else { - print("\(AppsFlyerConstants.errorPrefix)Must set an app_id and api_key in AppsFlyer Mobile Remote Command tag to initialize") - return - } - guard let settings = payload[AppsFlyerConstants.Configuration.settings] as? [String: Any] else { - return self.appsFlyerCommandTracker.initialize(appId: appId, appDevKey: appDevKey) - } - return self.appsFlyerCommandTracker.initialize(appId: appId, appDevKey: appDevKey, config: settings) - case .launch: - self.appsFlyerCommandTracker.trackLaunch() - case .trackLocation: - guard let latitude = payload[AppsFlyerConstants.Parameters.latitude] as? Double, - let longitude = payload[AppsFlyerConstants.Parameters.longitude] as? Double else { - print("\(AppsFlyerConstants.errorPrefix)Must map af_lat and af_long in the AppsFlyer Mobile Remote Command tag to track location") - return - } - self.appsFlyerCommandTracker.trackLocation(longitude: longitude, latitude: latitude) - case .setHost: - guard let host = payload[AppsFlyerConstants.Parameters.host] as? String, - let hostPrefix = payload[AppsFlyerConstants.Parameters.hostPrefix] as? String else { - print("\(AppsFlyerConstants.errorPrefix)Must map host and host_prefix in the AppsFlyer Mobile Remote Command tag to set host") - return - } - self.appsFlyerCommandTracker.setHost(host, with: hostPrefix) - case .setUserEmails: - guard let emails = payload[AppsFlyerConstants.Parameters.emails] as? [String], - let cryptType = payload[AppsFlyerConstants.Parameters.cryptType] as? Int else { - print("\(AppsFlyerConstants.errorPrefix)Must map customer_emails and cryptType in the AppsFlyer Mobile Remote Command tag to set user emails") - return - } - self.appsFlyerCommandTracker.setUserEmails(emails: emails, with: cryptType) - case .setCurrencyCode: - guard let currency = payload[AppsFlyerConstants.Parameters.currency] as? String else { - print("\(AppsFlyerConstants.errorPrefix)Must map af_currency in the AppsFlyer Mobile Remote Command tag to call set currency") - return - } - self.appsFlyerCommandTracker.currencyCode(currency) - case .setCustomerId: - guard let customerId = payload[AppsFlyerConstants.Parameters.customerId] as? String else { - print("\(AppsFlyerConstants.errorPrefix)Must map af_customer_user_id in the AppsFlyer Mobile Remote Command tag to call set customer id") - return - } - self.appsFlyerCommandTracker.customerId(customerId) - case .disableTracking: - guard let disable = payload[AppsFlyerConstants.Parameters.stopTracking] as? Bool else { - print("\(AppsFlyerConstants.errorPrefix)If you would like to disable all tracking, please set the enabled/disabled flag in the configuration settings of the AppsFlyer Mobile Remote Command tag") - return self.appsFlyerCommandTracker.disableTracking(false) - } - self.appsFlyerCommandTracker.disableTracking(disable) - case .resolveDeepLinkUrls: - guard let deepLinkUrls = payload[AppsFlyerConstants.Parameters.deepLinkUrls] as? [String] else { - print("\(AppsFlyerConstants.errorPrefix)If you would like to resolve deep link urls, please set the af_deep_link variable in the AppDelegate or AppsFlyer Mobile Remote Command tag") - return - } - self.appsFlyerCommandTracker.resolveDeepLinkURLs(deepLinkUrls) - default: - if let appsFlyerEvent = AppsFlyerConstants.EventCommandNames(rawValue: command.lowercased()) { - let eventName = String(standardEventName: appsFlyerEvent) - self.appsFlyerCommandTracker.trackEvent(eventName, values: payload) - } - break - } - } - } - -} - -fileprivate extension Dictionary where Key == String, Value == Any { - func filterVariables() -> [String: Any] { - self.filter { - $0.key != "debug" && - $0.key != "method" && - $0.key != AppsFlyerConstants.commandName - } - } -} - -fileprivate extension String { - init(standardEventName: AppsFlyerConstants.EventCommandNames) { - switch standardEventName { - case .achievelevel: - self = AppsFlyerConstants.Events.achievedLevel - case .adclick: - self = AppsFlyerConstants.Events.adClick - case .adview: - self = AppsFlyerConstants.Events.adView - case .addpaymentinfo: - self = AppsFlyerConstants.Events.addPaymentInfo - case .addtocart: - self = AppsFlyerConstants.Events.addToCart - case .addtowishlist: - self = AppsFlyerConstants.Events.addToWishlist - case .completeregistration: - self = AppsFlyerConstants.Events.completeRegistration - case .completetutorial: - self = AppsFlyerConstants.Events.completeTutorial - case .viewedcontent: - self = AppsFlyerConstants.Events.contentView - case .search: - self = AppsFlyerConstants.Events.search - case .rate: - self = AppsFlyerConstants.Events.rate - case .starttrial: - self = AppsFlyerConstants.Events.startTrial - case .subscribe: - self = AppsFlyerConstants.Events.subscribe - case .initiatecheckout: - self = AppsFlyerConstants.Events.initiateCheckout - case .purchase: - self = AppsFlyerConstants.Events.purchase - case .unlockachievement: - self = AppsFlyerConstants.Events.unlockAchievement - case .spentcredits: - self = AppsFlyerConstants.Events.spentCredits - case .listview: - self = AppsFlyerConstants.Events.listView - case .travelbooking: - self = AppsFlyerConstants.Events.travelBooking - case .share: - self = AppsFlyerConstants.Events.share - case .invite: - self = AppsFlyerConstants.Events.invite - case .reengage: - self = AppsFlyerConstants.Events.reEngage - case .update: - self = AppsFlyerConstants.Events.update - case .login: - self = AppsFlyerConstants.Events.login - case .customersegment: - self = AppsFlyerConstants.Events.customerSegment - } - } -} diff --git a/Objective-C/TealiumRegistration.swift b/Objective-C/TealiumRegistration.swift deleted file mode 100644 index 8f0216a..0000000 --- a/Objective-C/TealiumRegistration.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// TealiumRegistration.swift -// tealium-swift -// -// Created by Jonathan Wong on 1/17/19. -// Copyright © 2019 Tealium, Inc. All rights reserved. -// -#if os(OSX) -#else -import UIKit -import UserNotifications -#endif - -public protocol TealiumRegistration { - - func registerPushToken(_ token: String) - - func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) - - // Optional - @available(iOS 10.0, *) - func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) - - // Optional - func pushAuthorization(fromUserNotificationCenter: Bool) -} - -public extension TealiumRegistration { - - func pushAuthorization(fromUserNotificationCenter: Bool) { } - @available(iOS 10.0, *) - func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { } - -} diff --git a/Sources/AppsFlyerConstants.swift b/Sources/AppsFlyerConstants.swift index 541534a..83ddff8 100644 --- a/Sources/AppsFlyerConstants.swift +++ b/Sources/AppsFlyerConstants.swift @@ -12,6 +12,8 @@ public enum AppsFlyerConstants { static let commandName = "command_name" static let separator: Character = "," + static let commandId = "appsflyer" + static let description = "AppsFlyer Remote Command" static let errorPrefix = "AppsFlyer Error: " static let attributionLog = "AppsFlyer Attribution: " @@ -81,6 +83,7 @@ public enum AppsFlyerConstants { static let customerId = "af_customer_user_id" static let stopTracking = "stop_tracking" static let deepLinkUrls = "af_deep_link" + static let event = "event" } public enum Events { diff --git a/Sources/AppsFlyerCommandTracker.swift b/Sources/AppsFlyerInstance.swift similarity index 59% rename from Sources/AppsFlyerCommandTracker.swift rename to Sources/AppsFlyerInstance.swift index f8a2e40..b1dd018 100644 --- a/Sources/AppsFlyerCommandTracker.swift +++ b/Sources/AppsFlyerInstance.swift @@ -1,5 +1,5 @@ // -// AppsFlyerCommandTracker.swift +// AppsFlyerInstance.swift // TealiumAppsFlyer // // Created by Christina S on 5/29/19. @@ -12,17 +12,15 @@ import AppsFlyerLib import TealiumSwift #else import TealiumCore - import TealiumDelegate import TealiumTagManagement import TealiumRemoteCommands #endif -public protocol AppsFlyerTrackable { +public protocol AppsFlyerCommand { func initialize(appId: String, appDevKey: String, settings: [String: Any]?) - func trackLaunch() - func trackEvent(_ eventName: String, values: [String: Any]) - func trackLocation(longitude: Double, latitude: Double) + func logEvent(_ eventName: String, values: [String: Any]) + func logLocation(longitude: Double, latitude: Double) func setHost(_ host: String, with prefix: String) func setUserEmails(emails: [String], with cryptType: Int) func currencyCode(_ currency: String) @@ -31,7 +29,7 @@ public protocol AppsFlyerTrackable { func resolveDeepLinkURLs(_ urls: [String]) } -public class AppsFlyerCommandTracker: NSObject, AppsFlyerTrackable, TealiumRegistration { +public class AppsFlyerInstance: NSObject, AppsFlyerCommand, TealiumRegistration { weak var tealium: Tealium? @@ -40,82 +38,79 @@ public class AppsFlyerCommandTracker: NSObject, AppsFlyerTrackable, TealiumRegis public init(tealium: Tealium) { super.init() self.tealium = tealium - AppsFlyerTracker.shared().delegate = self + AppsFlyerLib.shared().delegate = self } public func initialize(appId: String, appDevKey: String, settings: [String: Any]?) { - AppsFlyerTracker.shared().appsFlyerDevKey = appDevKey - AppsFlyerTracker.shared().appleAppID = appId + AppsFlyerLib.shared().appsFlyerDevKey = appDevKey + AppsFlyerLib.shared().appleAppID = appId guard let settings = settings else { - AppsFlyerTracker.shared().appsFlyerDevKey = appDevKey - AppsFlyerTracker.shared().appleAppID = appId + AppsFlyerLib.shared().appsFlyerDevKey = appDevKey + AppsFlyerLib.shared().appleAppID = appId return } if let debug = settings[AppsFlyerConstants.Configuration.debug] as? Bool { - AppsFlyerTracker.shared().isDebug = debug + AppsFlyerLib.shared().isDebug = debug } if let disableAdTracking = settings[AppsFlyerConstants.Configuration.disableAdTracking] as? Bool { - AppsFlyerTracker.shared().disableIAdTracking = disableAdTracking + AppsFlyerLib.shared().disableAdvertisingIdentifier = disableAdTracking + AppsFlyerLib.shared().disableIDFVCollection = disableAdTracking } if let disableAppleAdTracking = settings[AppsFlyerConstants.Configuration.disableAppleAdTracking] as? Bool { - AppsFlyerTracker.shared().disableAppleAdSupportTracking = disableAppleAdTracking + AppsFlyerLib.shared().disableSKAdNetwork = disableAppleAdTracking } if let minTimeBetweenSessions = settings[AppsFlyerConstants.Configuration.minTimeBetweenSessions] as? Int { - AppsFlyerTracker.shared().minTimeBetweenSessions = UInt(minTimeBetweenSessions) + AppsFlyerLib.shared().minTimeBetweenSessions = UInt(minTimeBetweenSessions) } if let anonymizeUser = settings[AppsFlyerConstants.Configuration.anonymizeUser] as? Bool { - AppsFlyerTracker.shared().deviceTrackingDisabled = anonymizeUser + AppsFlyerLib.shared().anonymizeUser = anonymizeUser } if let shouldCollectDeviceName = settings[AppsFlyerConstants.Configuration.collectDeviceName] as? Bool { - AppsFlyerTracker.shared().shouldCollectDeviceName = shouldCollectDeviceName + AppsFlyerLib.shared().shouldCollectDeviceName = shouldCollectDeviceName } if let customData = settings[AppsFlyerConstants.Configuration.customData] as? [AnyHashable: Any] { - AppsFlyerTracker.shared().customData = customData + AppsFlyerLib.shared().customData = customData } } - public func trackLaunch() { - AppsFlyerTracker.shared().trackAppLaunch() + public func logEvent(_ eventName: String, values: [String: Any]) { + AppsFlyerLib.shared().logEvent(eventName, withValues: values) } - public func trackEvent(_ eventName: String, values: [String: Any]) { - AppsFlyerTracker.shared().trackEvent(eventName, withValues: values) - } - - public func trackLocation(longitude: Double, latitude: Double) { - AppsFlyerTracker.shared().trackLocation(longitude, latitude: latitude) + public func logLocation(longitude: Double, latitude: Double) { + AppsFlyerLib.shared().logLocation(longitude: longitude, latitude: latitude) } /// Used to track push notification activity from native APNs or other push service /// Please refer to this for more information: /// https://support.appsflyer.com/hc/en-us/articles/207364076-Measuring-Push-Notification-Re-Engagement-Campaigns public func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { - AppsFlyerTracker.shared().handlePushNotification(userInfo) - AppsFlyerTracker.shared().trackEvent(AppsFlyerConstants.Events.pushNotificationOpened, withValues: [:]) + AppsFlyerLib.shared().handlePushNotification(userInfo) + AppsFlyerLib.shared().logEvent(AppsFlyerConstants.Events.pushNotificationOpened, withValues: [:]) } public func handlePushNofification(payload: [String: Any]?) { - AppsFlyerTracker.shared().handlePushNotification(payload) + AppsFlyerLib.shared().handlePushNotification(payload) } public func setHost(_ host: String, with prefix: String) { - AppsFlyerTracker.shared().setHost(host, withHostPrefix: prefix) + AppsFlyerLib.shared().setHost(host, withHostPrefix: prefix) } public func setUserEmails(emails: [String], with cryptType: Int) { - AppsFlyerTracker.shared().setUserEmails(emails, with: EmailCryptType(rawValue: EmailCryptType.RawValue(cryptType))) + AppsFlyerLib.shared().setUserEmails(emails, with: EmailCryptType(rawValue: EmailCryptType.RawValue(cryptType))) } public func currencyCode(_ currency: String) { - AppsFlyerTracker.shared().currencyCode = currency + AppsFlyerLib.shared().currencyCode = currency } public func customerId(_ id: String) { - AppsFlyerTracker.shared().customerUserID = id + AppsFlyerLib.shared().customerUserID = id } public func disableTracking(_ disable: Bool) { - AppsFlyerTracker.shared().isStopTracking = disable + AppsFlyerLib.shared().isStopped = disable } /// APNs and Push Messaging must be configured in order to track installs. @@ -123,33 +118,28 @@ public class AppsFlyerCommandTracker: NSObject, AppsFlyerTrackable, TealiumRegis /// Instructions to set up: https://support.appsflyer.com/hc/en-us/articles/210289286-Uninstall-Measurement#iOS-Uninstall public func registerPushToken(_ token: String) { guard let dataToken = token.data(using: .utf8) else { return } - AppsFlyerTracker.shared().registerUninstall(dataToken) + AppsFlyerLib.shared().registerUninstall(dataToken) } public func resolveDeepLinkURLs(_ urls: [String]) { - AppsFlyerTracker.shared().resolveDeepLinkURLs = urls + AppsFlyerLib.shared().resolveDeepLinkURLs = urls } } -extension AppsFlyerCommandTracker: AppsFlyerTrackerDelegate { +extension AppsFlyerInstance: AppsFlyerLibDelegate { public func onConversionDataSuccess(_ conversionInfo: [AnyHashable: Any]) { - guard let tealium = tealium else { return } guard let conversionInfo = conversionInfo as? [String: Any], let firstLaunch = conversionInfo[AppsFlyerConstants.Attribution.firstLaunch] as? Bool else { - tealium.track(title: AppsFlyerConstants.Attribution.conversionReceived, - data: nil, - completion: nil) + tealiumTrack(title: AppsFlyerConstants.Attribution.conversionReceived) return } guard firstLaunch else { print("\(AppsFlyerConstants.attributionLog)Not First Launch") return } - tealium.track(title: AppsFlyerConstants.Attribution.conversionReceived, - data: conversionInfo, - completion: nil) + tealiumTrack(title: AppsFlyerConstants.Attribution.conversionReceived) guard let status = conversionInfo[AppsFlyerConstants.Attribution.status] as? String else { return @@ -166,29 +156,28 @@ extension AppsFlyerCommandTracker: AppsFlyerTrackerDelegate { } public func onConversionDataFail(_ error: Error) { - tealium?.track(title: AppsFlyerConstants.Attribution.error, + tealiumTrack(title: AppsFlyerConstants.Attribution.error, data: [AppsFlyerConstants.Attribution.errorName: AppsFlyerConstants.Attribution.conversionFailure, - AppsFlyerConstants.Attribution.errorDescription: error.localizedDescription], - completion: nil) + AppsFlyerConstants.Attribution.errorDescription: error.localizedDescription]) } public func onAppOpenAttribution(_ attributionData: [AnyHashable: Any]) { - guard let tealium = self.tealium else { return } guard let attributionData = attributionData as? [String: Any] else { - return tealium.track(title: AppsFlyerConstants.Attribution.appOpen, - data: nil, - completion: nil) + return tealiumTrack(title: AppsFlyerConstants.Attribution.appOpen) } - tealium.track(title: AppsFlyerConstants.Attribution.appOpen, - data: attributionData, - completion: nil) + tealiumTrack(title: AppsFlyerConstants.Attribution.appOpen, + data: attributionData) } public func onAppOpenAttributionFailure(_ error: Error) { - tealium?.track(title: AppsFlyerConstants.Attribution.error, + tealiumTrack(title: AppsFlyerConstants.Attribution.error, data: [AppsFlyerConstants.Attribution.errorName: AppsFlyerConstants.Attribution.appOpenFailure, - AppsFlyerConstants.Attribution.errorDescription: error.localizedDescription], - completion: nil) + AppsFlyerConstants.Attribution.errorDescription: error.localizedDescription]) + } + + private func tealiumTrack(title: String, data: [String: Any]? = nil) { + let event = TealiumEvent(title, dataLayer: data) + tealium?.track(event) } } diff --git a/Sources/AppsFlyerRemoteCommand.swift b/Sources/AppsFlyerRemoteCommand.swift index 35332f9..e622275 100644 --- a/Sources/AppsFlyerRemoteCommand.swift +++ b/Sources/AppsFlyerRemoteCommand.swift @@ -1,9 +1,9 @@ // // AppsFlyerRemoteCommand.swift -// AppsFlyerRemoteCommand +// TealiumAppsFlyer // // Created by Christina S on 5/29/19. -// Copyright © 2019 Christina. All rights reserved. +// Copyright © 2019 Tealium. All rights reserved. // import Foundation @@ -11,46 +11,41 @@ import Foundation import TealiumSwift #else import TealiumCore - import TealiumDelegate import TealiumTagManagement import TealiumRemoteCommands #endif -public class AppsFlyerRemoteCommand { +public class AppsFlyerRemoteCommand: RemoteCommand { - let appsFlyerCommandTracker: AppsFlyerTrackable + let appsFlyerInstance: AppsFlyerCommand? - public init(appsFlyerCommandTracker: AppsFlyerTrackable = AppsFlyerCommandTracker()) { - self.appsFlyerCommandTracker = appsFlyerCommandTracker - } - - public func remoteCommand() -> TealiumRemoteCommand { - return TealiumRemoteCommand(commandId: "appsflyer", description: "AppsFlyer Remote Command") { response in - var payload = response.payload() - if let disableTracking = payload[AppsFlyerConstants.Parameters.stopTracking] as? Bool { - if disableTracking == true { - self.appsFlyerCommandTracker.disableTracking(true) + public init(appsFlyerInstance: AppsFlyerCommand = AppsFlyerInstance(), type: RemoteCommandType = .webview) { + self.appsFlyerInstance = appsFlyerInstance + weak var selfWorkaround: AppsFlyerRemoteCommand? + super.init(commandId: AppsFlyerConstants.commandId, + description: AppsFlyerConstants.description, + type: type, + completion: { response in + guard let payload = response.payload else { return } - } - guard let command = payload[AppsFlyerConstants.commandName] as? String else { - return - } - let commands = command.split(separator: AppsFlyerConstants.separator) - let appsflyerCommands = commands.map { command in - return command.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) - } - payload = payload.filterVariables() - self.parseCommands(appsflyerCommands, payload: payload) - } + selfWorkaround?.processRemoteCommand(with: payload) + }) + selfWorkaround = self } - public func parseCommands(_ commands: [String], payload: [String: Any]) { - commands.forEach { [weak self] command in - let commandName = AppsFlyerConstants.CommandNames(rawValue: command.lowercased()) - guard let self = self else { + func processRemoteCommand(with payload: [String: Any]) { + guard let appsFlyerInstance = appsFlyerInstance, + let command = payload[AppsFlyerConstants.commandName] as? String else { return - } + } + let commands = command.split(separator: AppsFlyerConstants.separator) + let appsflyerCommands = commands.map { command in + return command.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + } + var debug = false + appsflyerCommands.forEach { + let commandName = AppsFlyerConstants.CommandNames(rawValue: $0.lowercased()) switch commandName { case .initialize: guard let appId = payload[AppsFlyerConstants.Configuration.appId] as? String, @@ -59,60 +54,87 @@ public class AppsFlyerRemoteCommand { return } guard let settings = payload[AppsFlyerConstants.Configuration.settings] as? [String: Any] else { - return self.appsFlyerCommandTracker.initialize(appId: appId, appDevKey: appDevKey, settings: nil) + return appsFlyerInstance.initialize(appId: appId, appDevKey: appDevKey, settings: nil) + } + if let settingsDebug = settings[AppsFlyerConstants.Configuration.debug] as? Bool { + debug = settingsDebug } - return self.appsFlyerCommandTracker.initialize(appId: appId, appDevKey: appDevKey, settings: settings) - case .launch: - self.appsFlyerCommandTracker.trackLaunch() + return appsFlyerInstance.initialize(appId: appId, appDevKey: appDevKey, settings: settings) case .trackLocation: guard let latitude = payload[AppsFlyerConstants.Parameters.latitude] as? Double, let longitude = payload[AppsFlyerConstants.Parameters.longitude] as? Double else { - print("\(AppsFlyerConstants.errorPrefix)Must map af_lat and af_long in the AppsFlyer Mobile Remote Command tag to track location") + guard let latitude = payload[AppsFlyerConstants.Parameters.latitude] as? Int, + let longitude = payload[AppsFlyerConstants.Parameters.longitude] as? Int else { + if debug { + print("\(AppsFlyerConstants.errorPrefix)Must map af_lat and af_long in the AppsFlyer Mobile Remote Command tag to track location") + } return + } + return appsFlyerInstance.logLocation(longitude: Double(longitude), latitude: Double(latitude)) } - self.appsFlyerCommandTracker.trackLocation(longitude: longitude, latitude: latitude) + appsFlyerInstance.logLocation(longitude: longitude, latitude: latitude) case .setHost: guard let host = payload[AppsFlyerConstants.Parameters.host] as? String, let hostPrefix = payload[AppsFlyerConstants.Parameters.hostPrefix] as? String else { + if debug { print("\(AppsFlyerConstants.errorPrefix)Must map host and host_prefix in the AppsFlyer Mobile Remote Command tag to set host") - return + + } + return } - self.appsFlyerCommandTracker.setHost(host, with: hostPrefix) + appsFlyerInstance.setHost(host, with: hostPrefix) case .setUserEmails: + var payload = payload + if let email = payload[AppsFlyerConstants.Parameters.emails] as? String { + payload[AppsFlyerConstants.Parameters.emails] = [email] + } guard let emails = payload[AppsFlyerConstants.Parameters.emails] as? [String], let cryptType = payload[AppsFlyerConstants.Parameters.cryptType] as? Int else { + if debug { print("\(AppsFlyerConstants.errorPrefix)Must map customer_emails and cryptType in the AppsFlyer Mobile Remote Command tag to set user emails") + } return } - self.appsFlyerCommandTracker.setUserEmails(emails: emails, with: cryptType) + appsFlyerInstance.setUserEmails(emails: emails, with: cryptType) case .setCurrencyCode: guard let currency = payload[AppsFlyerConstants.Parameters.currency] as? String else { - print("\(AppsFlyerConstants.errorPrefix)Must map af_currency in the AppsFlyer Mobile Remote Command tag to call set currency") + if debug { + print("\(AppsFlyerConstants.errorPrefix)Must map af_currency in the AppsFlyer Mobile Remote Command tag to call set currency") + } return } - self.appsFlyerCommandTracker.currencyCode(currency) + appsFlyerInstance.currencyCode(currency) case .setCustomerId: guard let customerId = payload[AppsFlyerConstants.Parameters.customerId] as? String else { - print("\(AppsFlyerConstants.errorPrefix)Must map af_customer_user_id in the AppsFlyer Mobile Remote Command tag to call set customer id") + if debug { + print("\(AppsFlyerConstants.errorPrefix)Must map af_customer_user_id in the AppsFlyer Mobile Remote Command tag to call set customer id") + } return } - self.appsFlyerCommandTracker.customerId(customerId) + appsFlyerInstance.customerId(customerId) case .disableTracking: guard let disable = payload[AppsFlyerConstants.Parameters.stopTracking] as? Bool else { - print("\(AppsFlyerConstants.errorPrefix)If you would like to disable all tracking, please set the enabled/disabled flag in the configuration settings of the AppsFlyer Mobile Remote Command tag") - return self.appsFlyerCommandTracker.disableTracking(false) + if debug { + print("\(AppsFlyerConstants.errorPrefix)If you would like to disable all tracking, please set the enabled/disabled flag in the configuration settings of the AppsFlyer Mobile Remote Command tag") + } + return appsFlyerInstance.disableTracking(false) } - self.appsFlyerCommandTracker.disableTracking(disable) + appsFlyerInstance.disableTracking(disable) case .resolveDeepLinkUrls: guard let deepLinkUrls = payload[AppsFlyerConstants.Parameters.deepLinkUrls] as? [String] else { - print("\(AppsFlyerConstants.errorPrefix)If you would like to resolve deep link urls, please set the af_deep_link variable in the AppDelegate or AppsFlyer Mobile Remote Command tag") + if debug { + print("\(AppsFlyerConstants.errorPrefix)If you would like to resolve deep link urls, please set the af_deep_link variable in the AppDelegate or AppsFlyer Mobile Remote Command tag") + } return } - self.appsFlyerCommandTracker.resolveDeepLinkURLs(deepLinkUrls) + appsFlyerInstance.resolveDeepLinkURLs(deepLinkUrls) default: - if let appsFlyerEvent = AppsFlyerConstants.EventCommandNames(rawValue: command.lowercased()) { + if let appsFlyerEvent = AppsFlyerConstants.EventCommandNames(rawValue: $0.lowercased()) { let eventName = String(standardEventName: appsFlyerEvent) - self.appsFlyerCommandTracker.trackEvent(eventName, values: payload) + guard let eventParameters = payload[AppsFlyerConstants.Parameters.event] as? [String: Any] else { + return appsFlyerInstance.logEvent(eventName, values: payload.filterVariables()) + } + appsFlyerInstance.logEvent(eventName, values: eventParameters) } break } @@ -124,10 +146,13 @@ public class AppsFlyerRemoteCommand { fileprivate extension Dictionary where Key == String, Value == Any { func filterVariables() -> [String: Any] { self.filter { - $0.key != "debug" && - $0.key != "method" && - $0.key != AppsFlyerConstants.commandName - } + $0.key != "debug" && + $0.key != "method" && + $0.key != "app_dev_key" && + $0.key != "app_id" && + $0.key != AppsFlyerConstants.commandName && + $0.key != "settings" + } } } @@ -186,4 +211,5 @@ fileprivate extension String { self = AppsFlyerConstants.Events.customerSegment } } + } diff --git a/TealiumAppsFlyer.podspec b/TealiumAppsFlyer.podspec index ad8b591..c2267ea 100644 --- a/TealiumAppsFlyer.podspec +++ b/TealiumAppsFlyer.podspec @@ -3,7 +3,7 @@ Pod::Spec.new do |s| # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # s.name = "TealiumAppsFlyer" s.module_name = "TealiumAppsFlyer" - s.version = "1.0.1" + s.version = "2.0.0" s.summary = "Tealium Swift and AppsFlyer integration" s.description = <<-DESC Tealium's integration with AppsFlyer for iOS. @@ -31,10 +31,9 @@ Pod::Spec.new do |s| # ――― Dependencies ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # s.static_framework = true - s.ios.dependency 'tealium-swift/Core', '~> 1.9' - s.ios.dependency 'tealium-swift/TealiumRemoteCommands', '~> 1.9' - s.ios.dependency 'tealium-swift/TealiumDelegate', '~> 1.9' - s.ios.dependency 'tealium-swift/TealiumTagManagement', '~> 1.9' - s.ios.dependency 'AppsFlyerFramework', '~> 5.2' + s.ios.dependency 'tealium-swift/Core', '~> 2.1' + s.ios.dependency 'tealium-swift/RemoteCommands', '~> 2.1' + s.ios.dependency 'tealium-swift/TagManagement', '~> 2.1' + s.ios.dependency 'AppsFlyerFramework', '~> 6.0' end diff --git a/TealiumAppsFlyer.xcodeproj/project.pbxproj b/TealiumAppsFlyer.xcodeproj/project.pbxproj index 571fb5e..3cf860d 100644 --- a/TealiumAppsFlyer.xcodeproj/project.pbxproj +++ b/TealiumAppsFlyer.xcodeproj/project.pbxproj @@ -7,21 +7,26 @@ objects = { /* Begin PBXBuildFile section */ + CF030DB5251E93EA002999B0 /* AppsFlyerLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFEDA03024626EEC004C9ED3 /* AppsFlyerLib.framework */; }; CF0D01FC232AB7CB005BFE15 /* TealiumAppsFlyer.h in Headers */ = {isa = PBXBuildFile; fileRef = CF0D01EE232AB7CB005BFE15 /* TealiumAppsFlyer.h */; settings = {ATTRIBUTES = (Public, ); }; }; CF0D0208232AB81A005BFE15 /* AppsFlyerRemoteCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF0D0205232AB81A005BFE15 /* AppsFlyerRemoteCommand.swift */; }; CF0D0209232AB81A005BFE15 /* AppsFlyerConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF0D0206232AB81A005BFE15 /* AppsFlyerConstants.swift */; }; - CF0D0211232AB848005BFE15 /* AppsFlyerCommandTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF0D020C232AB841005BFE15 /* AppsFlyerCommandTrackerTests.swift */; }; - CF0D0212232AB84B005BFE15 /* MockAppsFlyerCommandTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF0D020B232AB841005BFE15 /* MockAppsFlyerCommandTracker.swift */; }; - CF3F5C1223E258D10007C9B1 /* AppsFlyerCommandTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF3F5C1123E258D10007C9B1 /* AppsFlyerCommandTracker.swift */; }; + CF0D0211232AB848005BFE15 /* AppsFlyerInstanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF0D020C232AB841005BFE15 /* AppsFlyerInstanceTests.swift */; }; + CF0D0212232AB84B005BFE15 /* MockAppsFlyerInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF0D020B232AB841005BFE15 /* MockAppsFlyerInstance.swift */; }; + CF3277DF2522B5D500696BB4 /* TealiumRemoteCommands.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF3277DC2522B5D400696BB4 /* TealiumRemoteCommands.framework */; }; + CF3277E02522B5D500696BB4 /* TealiumRemoteCommands.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CF3277DC2522B5D400696BB4 /* TealiumRemoteCommands.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + CF3277E12522B5D500696BB4 /* TealiumTagManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF3277DD2522B5D400696BB4 /* TealiumTagManagement.framework */; }; + CF3277E22522B5D500696BB4 /* TealiumTagManagement.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CF3277DD2522B5D400696BB4 /* TealiumTagManagement.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + CF3277E32522B5D500696BB4 /* TealiumCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF3277DE2522B5D400696BB4 /* TealiumCore.framework */; }; + CF3277E42522B5D500696BB4 /* TealiumCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CF3277DE2522B5D400696BB4 /* TealiumCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + CF3277E92522B64E00696BB4 /* TealiumAppsFlyer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF0D01EB232AB7CB005BFE15 /* TealiumAppsFlyer.framework */; }; + CF3277EB2522B65C00696BB4 /* TealiumCore.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CF3277DE2522B5D400696BB4 /* TealiumCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + CF3277EC2522B65C00696BB4 /* TealiumRemoteCommands.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CF3277DC2522B5D400696BB4 /* TealiumRemoteCommands.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + CF3277ED2522B69F00696BB4 /* AppsFlyerConstants.swift in Headers */ = {isa = PBXBuildFile; fileRef = CF0D0206232AB81A005BFE15 /* AppsFlyerConstants.swift */; settings = {ATTRIBUTES = (Public, ); }; }; + CF3277EE2522B69F00696BB4 /* AppsFlyerRemoteCommand.swift in Headers */ = {isa = PBXBuildFile; fileRef = CF0D0205232AB81A005BFE15 /* AppsFlyerRemoteCommand.swift */; settings = {ATTRIBUTES = (Public, ); }; }; + CF3277EF2522B69F00696BB4 /* AppsFlyerInstance.swift in Headers */ = {isa = PBXBuildFile; fileRef = CF3F5C1123E258D10007C9B1 /* AppsFlyerInstance.swift */; settings = {ATTRIBUTES = (Public, ); }; }; + CF3F5C1223E258D10007C9B1 /* AppsFlyerInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF3F5C1123E258D10007C9B1 /* AppsFlyerInstance.swift */; }; CF9B51B8232AF23C003019F9 /* HttpTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF0D020F232AB847005BFE15 /* HttpTestHelpers.swift */; }; - CFEDA02724626EEB004C9ED3 /* TealiumTagManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF0D0222232AC591005BFE15 /* TealiumTagManagement.framework */; }; - CFEDA02924626EEB004C9ED3 /* TealiumRemoteCommands.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF0D0225232AC591005BFE15 /* TealiumRemoteCommands.framework */; }; - CFEDA02B24626EEB004C9ED3 /* TealiumDelegate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF0D0223232AC591005BFE15 /* TealiumDelegate.framework */; }; - CFEDA02D24626EEB004C9ED3 /* TealiumCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF0D0226232AC591005BFE15 /* TealiumCore.framework */; }; - CFEDA03124626EEC004C9ED3 /* AppsFlyerLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFEDA03024626EEC004C9ED3 /* AppsFlyerLib.framework */; }; - CFEDA03324626F1B004C9ED3 /* TealiumRemoteCommands.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF0D0225232AC591005BFE15 /* TealiumRemoteCommands.framework */; }; - CFEDA03424626F1B004C9ED3 /* TealiumCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF0D0226232AC591005BFE15 /* TealiumCore.framework */; }; - CFEDA03524626F1B004C9ED3 /* AppsFlyerLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFEDA03024626EEC004C9ED3 /* AppsFlyerLib.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -34,6 +39,33 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + CF3277E52522B5D500696BB4 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + CF3277E42522B5D500696BB4 /* TealiumCore.framework in Embed Frameworks */, + CF3277E22522B5D500696BB4 /* TealiumTagManagement.framework in Embed Frameworks */, + CF3277E02522B5D500696BB4 /* TealiumRemoteCommands.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + CF3277EA2522B65000696BB4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + CF3277EB2522B65C00696BB4 /* TealiumCore.framework in CopyFiles */, + CF3277EC2522B65C00696BB4 /* TealiumRemoteCommands.framework in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ CF0D01EB232AB7CB005BFE15 /* TealiumAppsFlyer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TealiumAppsFlyer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CF0D01EE232AB7CB005BFE15 /* TealiumAppsFlyer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TealiumAppsFlyer.h; sourceTree = ""; }; @@ -42,15 +74,13 @@ CF0D01FB232AB7CB005BFE15 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; CF0D0205232AB81A005BFE15 /* AppsFlyerRemoteCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppsFlyerRemoteCommand.swift; sourceTree = ""; }; CF0D0206232AB81A005BFE15 /* AppsFlyerConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppsFlyerConstants.swift; sourceTree = ""; }; - CF0D020B232AB841005BFE15 /* MockAppsFlyerCommandTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockAppsFlyerCommandTracker.swift; sourceTree = ""; }; - CF0D020C232AB841005BFE15 /* AppsFlyerCommandTrackerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppsFlyerCommandTrackerTests.swift; sourceTree = ""; }; + CF0D020B232AB841005BFE15 /* MockAppsFlyerInstance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockAppsFlyerInstance.swift; sourceTree = ""; }; + CF0D020C232AB841005BFE15 /* AppsFlyerInstanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppsFlyerInstanceTests.swift; sourceTree = ""; }; CF0D020F232AB847005BFE15 /* HttpTestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HttpTestHelpers.swift; sourceTree = ""; }; - CF0D0222232AC591005BFE15 /* TealiumTagManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TealiumTagManagement.framework; path = Carthage/Build/iOS/TealiumTagManagement.framework; sourceTree = ""; }; - CF0D0223232AC591005BFE15 /* TealiumDelegate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TealiumDelegate.framework; path = Carthage/Build/iOS/TealiumDelegate.framework; sourceTree = ""; }; - CF0D0224232AC591005BFE15 /* AppsFlyerTracker.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppsFlyerTracker.framework; path = Carthage/Build/iOS/AppsFlyerTracker.framework; sourceTree = ""; }; - CF0D0225232AC591005BFE15 /* TealiumRemoteCommands.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TealiumRemoteCommands.framework; path = Carthage/Build/iOS/TealiumRemoteCommands.framework; sourceTree = ""; }; - CF0D0226232AC591005BFE15 /* TealiumCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TealiumCore.framework; path = Carthage/Build/iOS/TealiumCore.framework; sourceTree = ""; }; - CF3F5C1123E258D10007C9B1 /* AppsFlyerCommandTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppsFlyerCommandTracker.swift; sourceTree = ""; }; + CF3277DC2522B5D400696BB4 /* TealiumRemoteCommands.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TealiumRemoteCommands.framework; path = Carthage/Build/iOS/TealiumRemoteCommands.framework; sourceTree = ""; }; + CF3277DD2522B5D400696BB4 /* TealiumTagManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TealiumTagManagement.framework; path = Carthage/Build/iOS/TealiumTagManagement.framework; sourceTree = ""; }; + CF3277DE2522B5D400696BB4 /* TealiumCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TealiumCore.framework; path = Carthage/Build/iOS/TealiumCore.framework; sourceTree = ""; }; + CF3F5C1123E258D10007C9B1 /* AppsFlyerInstance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppsFlyerInstance.swift; sourceTree = ""; }; CFEDA03024626EEC004C9ED3 /* AppsFlyerLib.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppsFlyerLib.framework; path = Carthage/Build/iOS/AppsFlyerLib.framework; sourceTree = ""; }; /* End PBXFileReference section */ @@ -59,11 +89,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CFEDA02924626EEB004C9ED3 /* TealiumRemoteCommands.framework in Frameworks */, - CFEDA02B24626EEB004C9ED3 /* TealiumDelegate.framework in Frameworks */, - CFEDA03124626EEC004C9ED3 /* AppsFlyerLib.framework in Frameworks */, - CFEDA02724626EEB004C9ED3 /* TealiumTagManagement.framework in Frameworks */, - CFEDA02D24626EEB004C9ED3 /* TealiumCore.framework in Frameworks */, + CF3277E12522B5D500696BB4 /* TealiumTagManagement.framework in Frameworks */, + CF3277DF2522B5D500696BB4 /* TealiumRemoteCommands.framework in Frameworks */, + CF030DB5251E93EA002999B0 /* AppsFlyerLib.framework in Frameworks */, + CF3277E32522B5D500696BB4 /* TealiumCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -71,9 +100,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CFEDA03324626F1B004C9ED3 /* TealiumRemoteCommands.framework in Frameworks */, - CFEDA03424626F1B004C9ED3 /* TealiumCore.framework in Frameworks */, - CFEDA03524626F1B004C9ED3 /* AppsFlyerLib.framework in Frameworks */, + CF3277E92522B64E00696BB4 /* TealiumAppsFlyer.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -104,7 +131,7 @@ children = ( CF0D0206232AB81A005BFE15 /* AppsFlyerConstants.swift */, CF0D0205232AB81A005BFE15 /* AppsFlyerRemoteCommand.swift */, - CF3F5C1123E258D10007C9B1 /* AppsFlyerCommandTracker.swift */, + CF3F5C1123E258D10007C9B1 /* AppsFlyerInstance.swift */, CF0D01EE232AB7CB005BFE15 /* TealiumAppsFlyer.h */, CF0D01EF232AB7CB005BFE15 /* Info.plist */, ); @@ -114,8 +141,8 @@ CF0D01F8232AB7CB005BFE15 /* Tests */ = { isa = PBXGroup; children = ( - CF0D020C232AB841005BFE15 /* AppsFlyerCommandTrackerTests.swift */, - CF0D020B232AB841005BFE15 /* MockAppsFlyerCommandTracker.swift */, + CF0D020C232AB841005BFE15 /* AppsFlyerInstanceTests.swift */, + CF0D020B232AB841005BFE15 /* MockAppsFlyerInstance.swift */, CF0D020F232AB847005BFE15 /* HttpTestHelpers.swift */, CF0D01FB232AB7CB005BFE15 /* Info.plist */, ); @@ -125,12 +152,10 @@ CF0D0221232AC590005BFE15 /* Frameworks */ = { isa = PBXGroup; children = ( + CF3277DE2522B5D400696BB4 /* TealiumCore.framework */, + CF3277DC2522B5D400696BB4 /* TealiumRemoteCommands.framework */, + CF3277DD2522B5D400696BB4 /* TealiumTagManagement.framework */, CFEDA03024626EEC004C9ED3 /* AppsFlyerLib.framework */, - CF0D0224232AC591005BFE15 /* AppsFlyerTracker.framework */, - CF0D0226232AC591005BFE15 /* TealiumCore.framework */, - CF0D0223232AC591005BFE15 /* TealiumDelegate.framework */, - CF0D0225232AC591005BFE15 /* TealiumRemoteCommands.framework */, - CF0D0222232AC591005BFE15 /* TealiumTagManagement.framework */, ); name = Frameworks; sourceTree = ""; @@ -143,6 +168,9 @@ buildActionMask = 2147483647; files = ( CF0D01FC232AB7CB005BFE15 /* TealiumAppsFlyer.h in Headers */, + CF3277ED2522B69F00696BB4 /* AppsFlyerConstants.swift in Headers */, + CF3277EE2522B69F00696BB4 /* AppsFlyerRemoteCommand.swift in Headers */, + CF3277EF2522B69F00696BB4 /* AppsFlyerInstance.swift in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -156,8 +184,7 @@ CF0D01E6232AB7CB005BFE15 /* Headers */, CF0D01E7232AB7CB005BFE15 /* Sources */, CF0D01E8232AB7CB005BFE15 /* Frameworks */, - CF0D01E9232AB7CB005BFE15 /* Resources */, - CF0D022C232AC5AC005BFE15 /* Carthage */, + CF3277E52522B5D500696BB4 /* Embed Frameworks */, ); buildRules = ( ); @@ -175,7 +202,7 @@ CF0D01F0232AB7CB005BFE15 /* Sources */, CF0D01F1232AB7CB005BFE15 /* Frameworks */, CF0D01F2232AB7CB005BFE15 /* Resources */, - CF0D022D232AC613005BFE15 /* Carthage */, + CF3277EA2522B65000696BB4 /* CopyFiles */, ); buildRules = ( ); @@ -225,13 +252,6 @@ /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - CF0D01E9232AB7CB005BFE15 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; CF0D01F2232AB7CB005BFE15 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -241,58 +261,13 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - CF0D022C232AC5AC005BFE15 /* Carthage */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(SRCROOT)/Carthage/Build/iOS/TealiumCore.framework", - "$(SRCROOT)/Carthage/Build/iOS/TealiumTagManagement.framework", - "$(SRCROOT)/Carthage/Build/iOS/TealiumRemoteCommands.framework", - "$(SRCROOT)/Carthage/Build/iOS/TealiumDelegate.framework", - ); - name = Carthage; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks\n"; - }; - CF0D022D232AC613005BFE15 /* Carthage */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(SRCROOT)/Carthage/Build/iOS/TealiumCore.framework", - "$(SRCROOT)/Carthage/Build/iOS/TealiumRemoteCommands.framework", - ); - name = Carthage; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks\n\n"; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ CF0D01E7232AB7CB005BFE15 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( CF0D0209232AB81A005BFE15 /* AppsFlyerConstants.swift in Sources */, - CF3F5C1223E258D10007C9B1 /* AppsFlyerCommandTracker.swift in Sources */, + CF3F5C1223E258D10007C9B1 /* AppsFlyerInstance.swift in Sources */, CF0D0208232AB81A005BFE15 /* AppsFlyerRemoteCommand.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -302,8 +277,8 @@ buildActionMask = 2147483647; files = ( CF9B51B8232AF23C003019F9 /* HttpTestHelpers.swift in Sources */, - CF0D0212232AB84B005BFE15 /* MockAppsFlyerCommandTracker.swift in Sources */, - CF0D0211232AB848005BFE15 /* AppsFlyerCommandTrackerTests.swift in Sources */, + CF0D0212232AB84B005BFE15 /* MockAppsFlyerInstance.swift in Sources */, + CF0D0211232AB848005BFE15 /* AppsFlyerInstanceTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -443,6 +418,7 @@ CF0D0200232AB7CB005BFE15 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; @@ -451,6 +427,8 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + EXCLUDED_ARCHS = ""; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", @@ -464,7 +442,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.tealium.TealiumAppsFlyer; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; + SKIP_INSTALL = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -474,6 +452,7 @@ CF0D0201232AB7CB005BFE15 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; @@ -483,6 +462,8 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_TESTABILITY = YES; + EXCLUDED_ARCHS = ""; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", @@ -496,7 +477,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.tealium.TealiumAppsFlyer; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; + SKIP_INSTALL = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/TealiumAppsFlyerExample/Podfile b/TealiumAppsFlyerExample/Podfile index 615b2da..c50f154 100644 --- a/TealiumAppsFlyerExample/Podfile +++ b/TealiumAppsFlyerExample/Podfile @@ -7,9 +7,6 @@ target 'TealiumAppsFlyerExample' do # Pods for TealiumAppsFlyerExample pod 'TealiumAppsFlyer', :path=> '../' - pod 'tealium-swift/TealiumLogger', '~> 1.9' - pod 'tealium-swift/TealiumTagManagement', '~> 1.9' - pod 'tealium-swift/TealiumAppData', '~> 1.9' - pod 'tealium-swift/TealiumDeviceData', '~> 1.9' - pod 'tealium-swift/TealiumLifecycle', '~> 1.9' + pod 'tealium-swift/Lifecycle', '~> 2.1' + end diff --git a/TealiumAppsFlyerExample/Podfile.lock b/TealiumAppsFlyerExample/Podfile.lock index f5802db..45baa44 100644 --- a/TealiumAppsFlyerExample/Podfile.lock +++ b/TealiumAppsFlyerExample/Podfile.lock @@ -1,33 +1,20 @@ PODS: - - AppsFlyerFramework (5.3.0) - - tealium-swift/Core (1.9.3) - - tealium-swift/TealiumAppData (1.9.3): + - AppsFlyerFramework (6.0.5) + - tealium-swift/Core (2.1.0) + - tealium-swift/Lifecycle (2.1.0): - tealium-swift/Core - - tealium-swift/TealiumDelegate (1.9.3): + - tealium-swift/RemoteCommands (2.1.0): - tealium-swift/Core - - tealium-swift/TealiumDeviceData (1.9.3): + - tealium-swift/TagManagement (2.1.0): - tealium-swift/Core - - tealium-swift/TealiumLifecycle (1.9.3): - - tealium-swift/Core - - tealium-swift/TealiumLogger (1.9.3): - - tealium-swift/Core - - tealium-swift/TealiumRemoteCommands (1.9.3): - - tealium-swift/Core - - tealium-swift/TealiumTagManagement (1.9.3): - - tealium-swift/Core - - TealiumAppsFlyer (1.0.1): - - AppsFlyerFramework (~> 5.2) - - tealium-swift/Core (~> 1.9) - - tealium-swift/TealiumDelegate (~> 1.9) - - tealium-swift/TealiumRemoteCommands (~> 1.9) - - tealium-swift/TealiumTagManagement (~> 1.9) + - TealiumAppsFlyer (2.0.0): + - AppsFlyerFramework (~> 6.0) + - tealium-swift/Core (~> 2.1) + - tealium-swift/RemoteCommands (~> 2.1) + - tealium-swift/TagManagement (~> 2.1) DEPENDENCIES: - - tealium-swift/TealiumAppData (~> 1.9) - - tealium-swift/TealiumDeviceData (~> 1.9) - - tealium-swift/TealiumLifecycle (~> 1.9) - - tealium-swift/TealiumLogger (~> 1.9) - - tealium-swift/TealiumTagManagement (~> 1.9) + - tealium-swift/Lifecycle (~> 2.1) - TealiumAppsFlyer (from `../`) SPEC REPOS: @@ -40,10 +27,10 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - AppsFlyerFramework: 122cc8b2de52f2b82ea739c2d9e57f919a9f5653 - tealium-swift: 8735caa69eeb0e7d834c290a6557c69c5f3667ee - TealiumAppsFlyer: 228f04c251cf65f5e58d51b2d869be7e10e0cd93 + AppsFlyerFramework: 3ae29222e2cb7d11cd176c71c780542979eb0c08 + tealium-swift: a670c2c6f3e7e5d775d9507387e8858a8541e526 + TealiumAppsFlyer: cdcb28677db8bb9db32d9a4b9d959325931560b8 -PODFILE CHECKSUM: 68d8c4712b44e4f174d0e596dbfbb3d13a666208 +PODFILE CHECKSUM: 5e5d01c67f2960f8dacbcbb4534dd06d2f20397e -COCOAPODS: 1.9.1 +COCOAPODS: 1.10.0 diff --git a/TealiumAppsFlyerExample/TealiumAppsFlyerExample.xcodeproj/project.pbxproj b/TealiumAppsFlyerExample/TealiumAppsFlyerExample.xcodeproj/project.pbxproj index 02f679b..255ca00 100644 --- a/TealiumAppsFlyerExample/TealiumAppsFlyerExample.xcodeproj/project.pbxproj +++ b/TealiumAppsFlyerExample/TealiumAppsFlyerExample.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + CF030DAA251E853F002999B0 /* appsflyer.json in Resources */ = {isa = PBXBuildFile; fileRef = CF030DA9251E853F002999B0 /* appsflyer.json */; }; CF1400C323036575002AC330 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF1400C223036575002AC330 /* AppDelegate.swift */; }; CF1400CA23036576002AC330 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CF1400C923036576002AC330 /* Assets.xcassets */; }; CF1400D5230365B9002AC330 /* TealiumHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF1400D4230365B9002AC330 /* TealiumHelper.swift */; }; @@ -26,12 +27,13 @@ CF14017E230366AF002AC330 /* Ecommerce.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CF14017D230366AF002AC330 /* Ecommerce.storyboard */; }; CF140181230366B7002AC330 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CF14017F230366B7002AC330 /* LaunchScreen.storyboard */; }; CF140182230366B7002AC330 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CF140180230366B7002AC330 /* Main.storyboard */; }; - EB7C8EE4EB7DA9E69235B033 /* Pods_TealiumAppsFlyerExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D217DA10B8AC86F5362F2FDD /* Pods_TealiumAppsFlyerExample.framework */; }; + CFB916D9FCB9714FA47D7BAE /* Pods_TealiumAppsFlyerExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA43EC996759F624B55C004F /* Pods_TealiumAppsFlyerExample.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 7D8F35250D16429EB06B1AC3 /* Pods-TealiumAppsFlyerExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TealiumAppsFlyerExample.debug.xcconfig"; path = "Target Support Files/Pods-TealiumAppsFlyerExample/Pods-TealiumAppsFlyerExample.debug.xcconfig"; sourceTree = ""; }; - CC351B32C456A094340F9628 /* Pods-TealiumAppsFlyerExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TealiumAppsFlyerExample.release.xcconfig"; path = "Target Support Files/Pods-TealiumAppsFlyerExample/Pods-TealiumAppsFlyerExample.release.xcconfig"; sourceTree = ""; }; + 2C949BD137A710096F1E29CE /* Pods-TealiumAppsFlyerExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TealiumAppsFlyerExample.debug.xcconfig"; path = "Target Support Files/Pods-TealiumAppsFlyerExample/Pods-TealiumAppsFlyerExample.debug.xcconfig"; sourceTree = ""; }; + CA43EC996759F624B55C004F /* Pods_TealiumAppsFlyerExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TealiumAppsFlyerExample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CF030DA9251E853F002999B0 /* appsflyer.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = appsflyer.json; sourceTree = ""; }; CF1400BF23036575002AC330 /* TealiumAppsFlyerExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TealiumAppsFlyerExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; CF1400C223036575002AC330 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; CF1400C923036576002AC330 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -54,7 +56,7 @@ CF14017F230366B7002AC330 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; CF140180230366B7002AC330 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; CFE3050323E20D9700A13B14 /* TealiumAppsFlyerExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TealiumAppsFlyerExample.entitlements; sourceTree = ""; }; - D217DA10B8AC86F5362F2FDD /* Pods_TealiumAppsFlyerExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TealiumAppsFlyerExample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F63E76748BB125BAA96DC98A /* Pods-TealiumAppsFlyerExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TealiumAppsFlyerExample.release.xcconfig"; path = "Target Support Files/Pods-TealiumAppsFlyerExample/Pods-TealiumAppsFlyerExample.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,28 +64,28 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - EB7C8EE4EB7DA9E69235B033 /* Pods_TealiumAppsFlyerExample.framework in Frameworks */, + CFB916D9FCB9714FA47D7BAE /* Pods_TealiumAppsFlyerExample.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 81E2F130CB92622A4A613A14 /* Pods */ = { + 45A2BC365AEC8CB0AEA3DD88 /* Frameworks */ = { isa = PBXGroup; children = ( - 7D8F35250D16429EB06B1AC3 /* Pods-TealiumAppsFlyerExample.debug.xcconfig */, - CC351B32C456A094340F9628 /* Pods-TealiumAppsFlyerExample.release.xcconfig */, + CA43EC996759F624B55C004F /* Pods_TealiumAppsFlyerExample.framework */, ); - path = Pods; + name = Frameworks; sourceTree = ""; }; - 96CB7726AE51A9D8F42E6F0E /* Frameworks */ = { + 81E2F130CB92622A4A613A14 /* Pods */ = { isa = PBXGroup; children = ( - D217DA10B8AC86F5362F2FDD /* Pods_TealiumAppsFlyerExample.framework */, + 2C949BD137A710096F1E29CE /* Pods-TealiumAppsFlyerExample.debug.xcconfig */, + F63E76748BB125BAA96DC98A /* Pods-TealiumAppsFlyerExample.release.xcconfig */, ); - name = Frameworks; + path = Pods; sourceTree = ""; }; CF1400B623036575002AC330 = { @@ -92,7 +94,7 @@ CF1400C123036575002AC330 /* TealiumAppsFlyerExample */, CF1400C023036575002AC330 /* Products */, 81E2F130CB92622A4A613A14 /* Pods */, - 96CB7726AE51A9D8F42E6F0E /* Frameworks */, + 45A2BC365AEC8CB0AEA3DD88 /* Frameworks */, ); sourceTree = ""; }; @@ -112,6 +114,7 @@ CF1400D6230365C2002AC330 /* DateExtensions.swift */, CF1400D7230365C3002AC330 /* ProductCell.swift */, CF1400C223036575002AC330 /* AppDelegate.swift */, + CF030DA9251E853F002999B0 /* appsflyer.json */, CF140183230366C0002AC330 /* Storyboard */, CF1400DA230365E4002AC330 /* View Controllers */, CF1400C923036576002AC330 /* Assets.xcassets */, @@ -155,11 +158,11 @@ isa = PBXNativeTarget; buildConfigurationList = CF1400D123036576002AC330 /* Build configuration list for PBXNativeTarget "TealiumAppsFlyerExample" */; buildPhases = ( - D1056CFF64F11361CF0799B7 /* [CP] Check Pods Manifest.lock */, + 5B12269D39D03F5E25475BC1 /* [CP] Check Pods Manifest.lock */, CF1400BB23036575002AC330 /* Sources */, CF1400BC23036575002AC330 /* Frameworks */, CF1400BD23036575002AC330 /* Resources */, - D56C0F5693FF788E38DE1CE1 /* [CP] Embed Pods Frameworks */, + 3B288E23525DE12B0BBA84E4 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -212,6 +215,7 @@ CF140182230366B7002AC330 /* Main.storyboard in Resources */, CF140181230366B7002AC330 /* LaunchScreen.storyboard in Resources */, CF14017C230366A8002AC330 /* Activities.storyboard in Resources */, + CF030DAA251E853F002999B0 /* appsflyer.json in Resources */, CF14017E230366AF002AC330 /* Ecommerce.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -219,43 +223,43 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - D1056CFF64F11361CF0799B7 /* [CP] Check Pods Manifest.lock */ = { + 3B288E23525DE12B0BBA84E4 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-TealiumAppsFlyerExample/Pods-TealiumAppsFlyerExample-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-TealiumAppsFlyerExample-checkManifestLockResult.txt", + "${PODS_ROOT}/Target Support Files/Pods-TealiumAppsFlyerExample/Pods-TealiumAppsFlyerExample-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TealiumAppsFlyerExample/Pods-TealiumAppsFlyerExample-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - D56C0F5693FF788E38DE1CE1 /* [CP] Embed Pods Frameworks */ = { + 5B12269D39D03F5E25475BC1 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-TealiumAppsFlyerExample/Pods-TealiumAppsFlyerExample-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-TealiumAppsFlyerExample/Pods-TealiumAppsFlyerExample-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-TealiumAppsFlyerExample-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TealiumAppsFlyerExample/Pods-TealiumAppsFlyerExample-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -403,7 +407,7 @@ }; CF1400D223036576002AC330 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7D8F35250D16429EB06B1AC3 /* Pods-TealiumAppsFlyerExample.debug.xcconfig */; + baseConfigurationReference = 2C949BD137A710096F1E29CE /* Pods-TealiumAppsFlyerExample.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = TealiumAppsFlyerExample/TealiumAppsFlyerExample.entitlements; @@ -423,7 +427,7 @@ }; CF1400D323036576002AC330 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = CC351B32C456A094340F9628 /* Pods-TealiumAppsFlyerExample.release.xcconfig */; + baseConfigurationReference = F63E76748BB125BAA96DC98A /* Pods-TealiumAppsFlyerExample.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = TealiumAppsFlyerExample/TealiumAppsFlyerExample.entitlements; diff --git a/TealiumAppsFlyerExample/TealiumAppsFlyerExample/AppDelegate.swift b/TealiumAppsFlyerExample/TealiumAppsFlyerExample/AppDelegate.swift index 4c57acb..0f8e487 100644 --- a/TealiumAppsFlyerExample/TealiumAppsFlyerExample/AppDelegate.swift +++ b/TealiumAppsFlyerExample/TealiumAppsFlyerExample/AppDelegate.swift @@ -30,8 +30,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { let deviceTokenString = String(format: "%@", deviceToken as CVarArg) // Use rc to register push token - tealiumHelper.pushMessagingTrackers.forEach { tracker in - tracker.registerPushToken(deviceTokenString) + tealiumHelper.pushMessaging.forEach { + $0.registerPushToken(deviceTokenString) } } @@ -47,8 +47,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // Use rc to log push notification receipt/open - tealiumHelper.pushMessagingTrackers.forEach { tracker in - tracker.application(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler) + tealiumHelper.pushMessaging.forEach { + $0.application(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler) } } @@ -58,8 +58,8 @@ extension AppDelegate: UNUserNotificationCenterDelegate { func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { // Use rc to log push notification receipt/open - tealiumHelper.pushMessagingTrackers.forEach { tracker in - tracker.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler) + tealiumHelper.pushMessaging.forEach { + $0.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler) } } @@ -72,8 +72,8 @@ extension AppDelegate: UNUserNotificationCenterDelegate { if granted { DispatchQueue.main.async { // use rc to log remote notification opt-in/out - self?.tealiumHelper.pushMessagingTrackers.forEach { tracker in - tracker.pushAuthorization(fromUserNotificationCenter: granted) + self?.tealiumHelper.pushMessaging.forEach { + $0.pushAuthorization(fromUserNotificationCenter: granted) } application.registerForRemoteNotifications() } diff --git a/TealiumAppsFlyerExample/TealiumAppsFlyerExample/TealiumHelper.swift b/TealiumAppsFlyerExample/TealiumAppsFlyerExample/TealiumHelper.swift index 0427fb1..c56f918 100644 --- a/TealiumAppsFlyerExample/TealiumAppsFlyerExample/TealiumHelper.swift +++ b/TealiumAppsFlyerExample/TealiumAppsFlyerExample/TealiumHelper.swift @@ -10,10 +10,6 @@ import Foundation import TealiumSwift import TealiumAppsFlyer -// Note: Due to a current bug in WebKit, you will see the following console error repeatedly: -// [Process] kill() returned unexpected error 1 -// Reference: https://bugs.webkit.org/show_bug.cgi?id=202173 and https://www.mail-archive.com/webkit-changes@lists.webkit.org/msg146193.html - enum TealiumConfiguration { static let account = "tealiummobile" static let profile = "appsflyer-tag" @@ -23,50 +19,46 @@ enum TealiumConfiguration { class TealiumHelper { static let shared = TealiumHelper() - var pushMessagingTrackers = [TealiumRegistration]() + var pushMessaging = [TealiumRegistration]() let config = TealiumConfig(account: TealiumConfiguration.account, profile: TealiumConfiguration.profile, environment: TealiumConfiguration.environment) var tealium: Tealium? + + // JSON Remote Command + let appsFlyerRemoteCommand = AppsFlyerRemoteCommand(type: .remote(url: "https://tags.tiqcdn.com/dle/tealiummobile/demo/appsflyer.json")) private init() { - config.logLevel = TealiumLogLevel.none config.shouldUseRemotePublishSettings = false - tealium = Tealium(config: config, - enableCompletion: { [weak self] _ in - guard let self = self else { return } - guard let remoteCommands = self.tealium?.remoteCommands() else { - return - } - // MARK: AppsFlyer - let appsFlyerCommandTracker = AppsFlyerCommandTracker() - let appsFlyerCommand = AppsFlyerRemoteCommand(appsFlyerCommandTracker: appsFlyerCommandTracker) - let appsFlyerRemoteCommand = appsFlyerCommand.remoteCommand() - remoteCommands.add(appsFlyerRemoteCommand) - self.pushMessagingTrackers.append(appsFlyerCommandTracker) - }) - + config.batchingEnabled = false + config.remoteAPIEnabled = true + config.logLevel = .info + config.collectors = [Collectors.Lifecycle] + config.dispatchers = [Dispatchers.TagManagement, Dispatchers.RemoteCommands] + + config.addRemoteCommand(appsFlyerRemoteCommand) + + tealium = Tealium(config: config) } - public func start() { _ = TealiumHelper.shared } class func trackView(title: String, data: [String: Any]?) { - TealiumHelper.shared.tealium?.track(title: title, data: data, completion: nil) + let tealiumView = TealiumView(title, dataLayer: data) + TealiumHelper.shared.tealium?.track(tealiumView) } class func trackScreen(_ view: UIViewController, name: String) { - TealiumHelper.trackView(title: "screen_view", - data: ["screen_name": name, - "screen_class": "\(view.classForCoder)"]) + TealiumHelper.trackView(title: "screen_view", data: ["screen_name": name, "screen_class": "\(view.classForCoder)"]) } class func trackEvent(title: String, data: [String: Any]?) { - TealiumHelper.shared.tealium?.track(title: title, data: data, completion: nil) + let tealiumEvent = TealiumEvent(title, dataLayer: data) + TealiumHelper.shared.tealium?.track(tealiumEvent) } } diff --git a/TealiumAppsFlyerExample/TealiumAppsFlyerExample/appsflyer.json b/TealiumAppsFlyerExample/TealiumAppsFlyerExample/appsflyer.json new file mode 100644 index 0000000..5568a8f --- /dev/null +++ b/TealiumAppsFlyerExample/TealiumAppsFlyerExample/appsflyer.json @@ -0,0 +1,69 @@ +{ + "config": { + "app_id": "test", + "app_dev_key": "test", + "settings": { + "custom_data": {"custom_key": "custom_value"}, + "debug": true, + "disable_ad_tracking": false, + "disable_apple_ad_tracking": false, + "time_between_sessions": 30, + "anonymize_user": false, + "collect_device_name": false + } + }, + "mappings": { + "latitude": "af_lat", + "longitude": "af_long", + "customer_email": "customer_emails", + "hash_type": "email_hash_type", + "currency_code": "af_currency", + "customer_id": "af_customer_user_id", + "signup_method": "event.signup_method", + "achievement_id": "event.achievement_id", + "checkout_option": "event.checkout_option", + "checkout_step": "event.checkout_step", + "content": "event.content", + "content_type": "event.content_type", + "coupon": "event.coupon", + "product_brand": "event.product_brand", + "product_category": "event.product_category", + "product_id": "event.af_content_id", + "product_list": "event.product_list", + "product_location_id": "event.product_location_id", + "product_name": "event.product_name", + "product_variant": "event.product_variant", + "product_unit_price": "event.af_price", + "product_quantity": "event.af_quantity", + "current_level": "event.level", + "score": "event.score", + "search_keyword": "event.search_keyword", + "order_shipping_amount": "event.order_shipping", + "order_tax_amount": "event.order_tax", + "order_id": "event.af_order_id", + "order_total": "event.af_revenue", + "currency_type": "event.currency_type" + }, + "commands": { + "launch": "initialize,launch", + "geofence_entered": "tracklocation", + "geofence_exited": "tracklocation", + "track_location": "tracklocation", + "user_login": "login", + "user_register": "setuseremails,setcustomerid,completeregistration", + "show_offers": "adclick", + "cart_add": "addtocart", + "wishlist_add": "addtowishlist", + "payment": "addpaymentinfo", + "unlock_achievement": "unlockachievement", + "level_up": "achievelevel,customersegment", + "email_signup": "subscribe", + "product": "viewedcontent", + "category": "listview", + "share": "share", + "rate": "rate", + "search": "search", + "checkout": "initiatecheckout", + "order":"purchase" + } +} diff --git a/Tests/AppsFlyerCommandTrackerTests.swift b/Tests/AppsFlyerCommandTrackerTests.swift deleted file mode 100644 index 79cd401..0000000 --- a/Tests/AppsFlyerCommandTrackerTests.swift +++ /dev/null @@ -1,352 +0,0 @@ -// -// AppsFlyerRemoteCommandTests.swift -// AppsFlyerRemoteCommandTests -// -// Created by Christina S on 5/24/19. -// Copyright © 2019 Christina. All rights reserved. -// - -import XCTest -@testable import TealiumAppsFlyer -import TealiumRemoteCommands - - -class AppsFlyerCommandTrackerTests: XCTestCase { - - var appsFlyerCommandTracker = MockAppsFlyerCommandTracker() - var appsFlyerCommand: AppsFlyerRemoteCommand! - var remoteCommand: TealiumRemoteCommand! - - override func setUp() { - appsFlyerCommand = AppsFlyerRemoteCommand(appsFlyerCommandTracker: appsFlyerCommandTracker) - remoteCommand = appsFlyerCommand.remoteCommand() - } - - func createRemoteCommandResponse(commandId: String, payload: [String: Any]) -> TealiumRemoteCommandResponse? { - let responseDescription = HttpTestHelpers.httpRequestDescription(commandId: commandId, config: [:], payload: payload) - if let description = responseDescription { - return TealiumRemoteCommandResponse(urlString: description) - } - XCTFail("Could not create Remote Command Response description from stubs provided") - return nil - } - - override func tearDown() { } - - func testInitWithoutConfig() { - let expect = expectation(description: "AppsFlyerRunner initialize(appId:appDevKey:) method run") - let payload: [String: Any] = ["command_name": "initialize", - "app_id": "test", - "app_dev_key": "test"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(1, self.appsFlyerCommandTracker.initWithoutConfigCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testInitWithoutConfigNotRun() { - let expect = expectation(description: "AppsFlyerRunner initialize(appId:appDevKey:) method does not run") - let payload: [String: Any] = ["command_name": "initialize"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(0, self.appsFlyerCommandTracker.initWithoutConfigCount) - XCTAssertEqual(0, self.appsFlyerCommandTracker.initWithConfigCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testInitWithConfig() { - let expect = expectation(description: "AppsFlyerRunner initialize(appId:appDevKey:settings:) method run") - let payload: [String: Any] = ["command_name": "initialize", - "app_id": "test", - "app_dev_key": "test", - "settings": ["test": "test"]] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(1, self.appsFlyerCommandTracker.initWithConfigCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testInitWithConfigNotRun() { - let expect = expectation(description: "AppsFlyerRunner initialize(appId:appDevKey:settings:) method does not run") - let payload: [String: Any] = ["command_name": "initialize", - "settings": ["test": "test"]] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(0, self.appsFlyerCommandTracker.initWithConfigCount) - XCTAssertEqual(0, self.appsFlyerCommandTracker.initWithConfigCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testTrackLaunch() { - let expect = expectation(description: "AppsFlyerRunner trackLaunch() method run") - let payload: [String: Any] = ["command_name": "launch"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(1, self.appsFlyerCommandTracker.trackLaunchCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testTrackLaunchNotRun() { - let expect = expectation(description: "AppsFlyerRunner trackLaunch() method does not run") - let payload: [String: Any] = ["command_name": "tracklaunch"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(0, self.appsFlyerCommandTracker.trackLaunchCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testTrackEvent() { - let expect = expectation(description: "AppsFlyerRunner trackEvent(eventName:values:) method run") - let payload: [String: Any] = ["command_name": "viewedcontent,rate,login"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(3, self.appsFlyerCommandTracker.trackEventCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testTrackEventNotRun() { - let expect = expectation(description: "AppsFlyerRunner trackEvent(eventName:values:) method run") - let payload: [String: Any] = ["command_name": "unrecognized,nope,test"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(0, self.appsFlyerCommandTracker.trackEventCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testTrackLocation() { - let expect = expectation(description: "AppsFlyerRunner trackLocation(longitude:latitude:) method run") - let payload: [String: Any] = ["command_name": "tracklocation", - "af_lat": 33, - "af_long": 122] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(1, self.appsFlyerCommandTracker.trackLocationCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testTrackLocationNotRun() { - let expect = expectation(description: "AppsFlyerRunner trackLocation(longitude:latitude:) method has not run") - let payload: [String: Any] = ["command_name": "tracklocation"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(0, self.appsFlyerCommandTracker.trackLocationCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testSetHost() { - let expect = expectation(description: "AppsFlyerRunner setHost(_ host:with:) method run") - let payload: [String: Any] = ["command_name": "sethost", - "host": "test.com", - "host_prefix": "test"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(1, self.appsFlyerCommandTracker.setHostCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testSetHostNotRun() { - let expect = expectation(description: "AppsFlyerRunner setHost(_ host:with:) method has not run") - let payload: [String: Any] = ["command_name": "sethost", - "host_prefix": "test"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(0, self.appsFlyerCommandTracker.setHostCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testSetUserEmails() { - let expect = expectation(description: "AppsFlyerRunner setUserEmails(emails:with:) method run") - let payload: [String: Any] = ["command_name": "setuseremails", - "customer_emails": ["blah", "blah2"], - "email_hash_type": 1] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(1, self.appsFlyerCommandTracker.setUserEmailsCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testSetUserEmailsWNotRun() { - let expect = expectation(description: "AppsFlyerRunner setUserEmails(emails:with:) method has not run") - let payload: [String: Any] = ["command_name": "setuseremails", - "email_hash_type": 1] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(0, self.appsFlyerCommandTracker.setUserEmailsCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testSetCurrencyCode() { - let expect = expectation(description: "AppsFlyerRunner currencyCode(currency:) method run") - let payload: [String: Any] = ["command_name": "setcurrencycode", "af_currency": "USD"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(1, self.appsFlyerCommandTracker.setCurrencyCodeCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testSetCurrencyCodeNotRun() { - let expect = expectation(description: "AppsFlyerRunner currencyCode(currency:) method has not run") - let payload: [String: Any] = ["command_name": "setcurrencycode"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(0, self.appsFlyerCommandTracker.setCurrencyCodeCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testSetCustomerId() { - let expect = expectation(description: "AppsFlyerRunner customerId(id:) method run") - let payload: [String: Any] = ["command_name": "setcustomerid", "af_customer_user_id": "ABC123"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(1, self.appsFlyerCommandTracker.setCustomerIdCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testSetCustomerIdNotRun() { - let expect = expectation(description: "AppsFlyerRunner customerId(id:) method has not run") - let payload: [String: Any] = ["command_name": "setcustomerid"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(0, self.appsFlyerCommandTracker.setCustomerIdCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testDisableTrackingCommandName() { - let expect = expectation(description: "AppsFlyerRunner disableTracking(disable:) method run") - let payload: [String: Any] = ["command_name": "disabletracking"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(1, self.appsFlyerCommandTracker.disableTrackingCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testDisableTrackingNotRun() { - let expect = expectation(description: "AppsFlyerRunner disableTracking(disable:) method has not run") - let payload: [String: Any] = ["command_name": "disable"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(0, self.appsFlyerCommandTracker.disableTrackingCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testDisableTrackingVariable() { - let expect = expectation(description: "AppsFlyerRunner disableTracking(disable:) method run") - let payload: [String: Any] = ["command_name": "disabletracking"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(1, self.appsFlyerCommandTracker.disableTrackingCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testResolveDeepLinkURLs() { - let expect = expectation(description: "AppsFlyerRunner resolveDeepLinkURLs(urls:) method run") - let payload: [String: Any] = ["command_name": "resolvedeeplinkurls", "af_deep_link": ["app://test.com", "app://test?home=true"]] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(1, self.appsFlyerCommandTracker.resolveDeepLinkURLsCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - func testResolveDeepLinkURLsNotRun() { - let expect = expectation(description: "AppsFlyerRunner resolveDeepLinkURLs(urls:) method has not run") - let payload: [String: Any] = ["command_name": "resolvedeeplinkurls"] - - if let response = createRemoteCommandResponse(commandId: "appsflyer", payload: payload) { - remoteCommand.remoteCommandCompletion(response) - XCTAssertEqual(0, self.appsFlyerCommandTracker.resolveDeepLinkURLsCount) - } - - expect.fulfill() - wait(for: [expect], timeout: 5.0) - } - - -} diff --git a/Tests/AppsFlyerInstanceTests.swift b/Tests/AppsFlyerInstanceTests.swift new file mode 100644 index 0000000..cfefd68 --- /dev/null +++ b/Tests/AppsFlyerInstanceTests.swift @@ -0,0 +1,637 @@ +// +// AppsFlyerRemoteCommandTests.swift +// TealiumAppsFlyerTests +// +// Created by Christina S on 5/24/19. +// Copyright © 2019 Tealium. All rights reserved. +// + +import XCTest +@testable import TealiumAppsFlyer +import TealiumRemoteCommands + + +class AppsFlyerInstanceTests: XCTestCase { + + var appsFlyerInstance = MockAppsFlyerInstance() + var appsFlyerCommand: AppsFlyerRemoteCommand! + + override func setUp() { + appsFlyerCommand = AppsFlyerRemoteCommand(appsFlyerInstance: appsFlyerInstance) + } + + override func tearDown() { } + + + // MARK: Webview Remote Command Tests + + func testInitWithoutConfig() { + let expect = expectation(description: "AppsFlyerRunner initialize(appId:appDevKey:) method run") + let payload: [String: Any] = ["command_name": "initialize", + "app_id": "test", + "app_dev_key": "test"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.initWithoutConfigCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testInitWithoutConfigNotRun() { + let expect = expectation(description: "AppsFlyerRunner initialize(appId:appDevKey:) method does not run") + let payload: [String: Any] = ["command_name": "initialize"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.initWithoutConfigCount) + XCTAssertEqual(0, self.appsFlyerInstance.initWithConfigCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testInitWithConfig() { + let expect = expectation(description: "AppsFlyerRunner initialize(appId:appDevKey:settings:) method run") + let payload: [String: Any] = ["command_name": "initialize", + "app_id": "test", + "app_dev_key": "test", + "settings": ["test": "test"]] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.initWithConfigCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testInitWithConfigNotRun() { + let expect = expectation(description: "AppsFlyerRunner initialize(appId:appDevKey:settings:) method does not run") + let payload: [String: Any] = ["command_name": "initialize", + "settings": ["test": "test"]] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.initWithConfigCount) + XCTAssertEqual(0, self.appsFlyerInstance.initWithConfigCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testTrackEvent() { + let expect = expectation(description: "AppsFlyerRunner trackEvent(eventName:values:) method run") + let payload: [String: Any] = ["command_name": "viewedcontent,rate,login"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(3, self.appsFlyerInstance.logEventCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testTrackEventNotRun() { + let expect = expectation(description: "AppsFlyerRunner trackEvent(eventName:values:) method run") + let payload: [String: Any] = ["command_name": "unrecognized,nope,test"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.logEventCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testTrackLocationWithLatLongInts() { + let expect = expectation(description: "AppsFlyerRunner trackLocation(longitude:latitude:) method run") + let payload: [String: Any] = ["command_name": "tracklocation", + "af_lat": 33, + "af_long": 122] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.logLocationCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testTrackLocationWithLatLongDoubles() { + let expect = expectation(description: "AppsFlyerRunner trackLocation(longitude:latitude:) method run") + let payload: [String: Any] = ["command_name": "tracklocation", + "af_lat": 33.0, + "af_long": -122.0] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.logLocationCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testTrackLocationNotRun() { + let expect = expectation(description: "AppsFlyerRunner trackLocation(longitude:latitude:) method has not run") + let payload: [String: Any] = ["command_name": "tracklocation"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.logLocationCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetHost() { + let expect = expectation(description: "AppsFlyerRunner setHost(_ host:with:) method run") + let payload: [String: Any] = ["command_name": "sethost", + "host": "test.com", + "host_prefix": "test"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.setHostCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetHostNotRun() { + let expect = expectation(description: "AppsFlyerRunner setHost(_ host:with:) method has not run") + let payload: [String: Any] = ["command_name": "sethost", + "host_prefix": "test"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.setHostCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetUserEmails() { + let expect = expectation(description: "AppsFlyerRunner setUserEmails(emails:with:) method run") + let payload: [String: Any] = ["command_name": "setuseremails", + "customer_emails": ["blah", "blah2"], + "email_hash_type": 1] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.setUserEmailsCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetUserEmailsWNotRun() { + let expect = expectation(description: "AppsFlyerRunner setUserEmails(emails:with:) method has not run") + let payload: [String: Any] = ["command_name": "setuseremails", + "email_hash_type": 1] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.setUserEmailsCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetCurrencyCode() { + let expect = expectation(description: "AppsFlyerRunner currencyCode(currency:) method run") + let payload: [String: Any] = ["command_name": "setcurrencycode", "af_currency": "USD"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.setCurrencyCodeCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetCurrencyCodeNotRun() { + let expect = expectation(description: "AppsFlyerRunner currencyCode(currency:) method has not run") + let payload: [String: Any] = ["command_name": "setcurrencycode"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.setCurrencyCodeCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetCustomerId() { + let expect = expectation(description: "AppsFlyerRunner customerId(id:) method run") + let payload: [String: Any] = ["command_name": "setcustomerid", "af_customer_user_id": "ABC123"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.setCustomerIdCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetCustomerIdNotRun() { + let expect = expectation(description: "AppsFlyerRunner customerId(id:) method has not run") + let payload: [String: Any] = ["command_name": "setcustomerid"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.setCustomerIdCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testDisableTrackingCommandName() { + let expect = expectation(description: "AppsFlyerRunner disableTracking(disable:) method run") + let payload: [String: Any] = ["command_name": "disabletracking"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.disableTrackingCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testDisableTrackingNotRun() { + let expect = expectation(description: "AppsFlyerRunner disableTracking(disable:) method has not run") + let payload: [String: Any] = ["command_name": "disable"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.disableTrackingCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testDisableTrackingVariable() { + let expect = expectation(description: "AppsFlyerRunner disableTracking(disable:) method run") + let payload: [String: Any] = ["command_name": "disabletracking"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.disableTrackingCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testResolveDeepLinkURLs() { + let expect = expectation(description: "AppsFlyerRunner resolveDeepLinkURLs(urls:) method run") + let payload: [String: Any] = ["command_name": "resolvedeeplinkurls", "af_deep_link": ["app://test.com", "app://test?home=true"]] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.resolveDeepLinkURLsCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testResolveDeepLinkURLsNotRun() { + let expect = expectation(description: "AppsFlyerRunner resolveDeepLinkURLs(urls:) method has not run") + let payload: [String: Any] = ["command_name": "resolvedeeplinkurls"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .webview, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.resolveDeepLinkURLsCount) + } + + wait(for: [expect], timeout: 2.0) + } + + // MARK: JSON Remote Command Tests + + func testInitWithoutConfigJSON() { + let expect = expectation(description: "AppsFlyerRunner initialize(appId:appDevKey:) method run") + let payload: [String: Any] = ["command_name": "initialize", + "app_id": "test", + "app_dev_key": "test"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.initWithoutConfigCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testInitWithoutConfigNotRunJSON() { + let expect = expectation(description: "AppsFlyerRunner initialize(appId:appDevKey:) method does not run") + let payload: [String: Any] = ["command_name": "initialize"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.initWithoutConfigCount) + XCTAssertEqual(0, self.appsFlyerInstance.initWithConfigCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testInitWithConfigJSON() { + let expect = expectation(description: "AppsFlyerRunner initialize(appId:appDevKey:settings:) method run") + let payload: [String: Any] = ["command_name": "initialize", + "app_id": "test", + "app_dev_key": "test", + "settings": ["test": "test"]] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.initWithConfigCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testInitWithConfigNotRunJSON() { + let expect = expectation(description: "AppsFlyerRunner initialize(appId:appDevKey:settings:) method does not run") + let payload: [String: Any] = ["command_name": "initialize", + "settings": ["test": "test"]] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.initWithConfigCount) + XCTAssertEqual(0, self.appsFlyerInstance.initWithConfigCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testTrackEventJSON() { + let expect = expectation(description: "AppsFlyerRunner trackEvent(eventName:values:) method run") + let payload: [String: Any] = ["command_name": "viewedcontent,rate,login"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(3, self.appsFlyerInstance.logEventCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testTrackEventNotRunJSON() { + let expect = expectation(description: "AppsFlyerRunner trackEvent(eventName:values:) method does not run") + let payload: [String: Any] = ["command_name": "unrecognized,nope,test"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.logEventCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testTrackLocationWithLatLongIntsJSON() { + let expect = expectation(description: "AppsFlyerRunner trackLocation(longitude:latitude:) method run") + let payload: [String: Any] = ["command_name": "tracklocation", + "af_lat": 33, + "af_long": 122] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.logLocationCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testTrackLocationWithLatLongDoublesJSON() { + let expect = expectation(description: "AppsFlyerRunner trackLocation(longitude:latitude:) method run") + let payload: [String: Any] = ["command_name": "tracklocation", + "af_lat": 33.0, + "af_long": -122.0] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.logLocationCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testTrackLocationNotRunJSON() { + let expect = expectation(description: "AppsFlyerRunner trackLocation(longitude:latitude:) method has not run") + let payload: [String: Any] = ["command_name": "tracklocation"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.logLocationCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetHostJSON() { + let expect = expectation(description: "AppsFlyerRunner setHost(_ host:with:) method run") + let payload: [String: Any] = ["command_name": "sethost", + "host": "test.com", + "host_prefix": "test"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.setHostCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetHostNotRunJSON() { + let expect = expectation(description: "AppsFlyerRunner setHost(_ host:with:) method has not run") + let payload: [String: Any] = ["command_name": "sethost", + "host_prefix": "test"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.setHostCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetUserEmailsJSON() { + let expect = expectation(description: "AppsFlyerRunner setUserEmails(emails:with:) method run") + let payload: [String: Any] = ["command_name": "setuseremails", + "customer_emails": ["blah", "blah2"], + "email_hash_type": 1] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.setUserEmailsCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetUserEmailsWNotRunJSON() { + let expect = expectation(description: "AppsFlyerRunner setUserEmails(emails:with:) method has not run") + let payload: [String: Any] = ["command_name": "setuseremails", + "email_hash_type": 1] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.setUserEmailsCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetCurrencyCodeJSON() { + let expect = expectation(description: "AppsFlyerRunner currencyCode(currency:) method run") + let payload: [String: Any] = ["command_name": "setcurrencycode", "af_currency": "USD"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.setCurrencyCodeCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetCurrencyCodeNotRunJSON() { + let expect = expectation(description: "AppsFlyerRunner currencyCode(currency:) method has not run") + let payload: [String: Any] = ["command_name": "setcurrencycode"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.setCurrencyCodeCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetCustomerIdJSON() { + let expect = expectation(description: "AppsFlyerRunner customerId(id:) method run") + let payload: [String: Any] = ["command_name": "setcustomerid", "af_customer_user_id": "ABC123"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.setCustomerIdCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testSetCustomerIdNotRunJSON() { + let expect = expectation(description: "AppsFlyerRunner customerId(id:) method has not run") + let payload: [String: Any] = ["command_name": "setcustomerid"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.setCustomerIdCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testDisableTrackingCommandNameJSON() { + let expect = expectation(description: "AppsFlyerRunner disableTracking(disable:) method run") + let payload: [String: Any] = ["command_name": "disabletracking"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.disableTrackingCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testDisableTrackingNotRunJSON() { + let expect = expectation(description: "AppsFlyerRunner disableTracking(disable:) method has not run") + let payload: [String: Any] = ["command_name": "disable"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.disableTrackingCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testDisableTrackingVariableJSON() { + let expect = expectation(description: "AppsFlyerRunner disableTracking(disable:) method run") + let payload: [String: Any] = ["command_name": "disabletracking"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.disableTrackingCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testResolveDeepLinkURLsJSON() { + let expect = expectation(description: "AppsFlyerRunner resolveDeepLinkURLs(urls:) method run") + let payload: [String: Any] = ["command_name": "resolvedeeplinkurls", "af_deep_link": ["app://test.com", "app://test?home=true"]] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(1, self.appsFlyerInstance.resolveDeepLinkURLsCount) + } + + wait(for: [expect], timeout: 2.0) + } + + func testResolveDeepLinkURLsNotRunJSON() { + let expect = expectation(description: "AppsFlyerRunner resolveDeepLinkURLs(urls:) method has not run") + let payload: [String: Any] = ["command_name": "resolvedeeplinkurls"] + + if let response = HttpTestHelpers.createRemoteCommandResponse(type: .JSON, commandId: "appsflyer", payload: payload) { + appsFlyerCommand.completion(response) + expect.fulfill() + XCTAssertEqual(0, self.appsFlyerInstance.resolveDeepLinkURLsCount) + } + + wait(for: [expect], timeout: 2.0) + } +} diff --git a/Tests/HttpTestHelpers.swift b/Tests/HttpTestHelpers.swift index d25ca35..f219d07 100644 --- a/Tests/HttpTestHelpers.swift +++ b/Tests/HttpTestHelpers.swift @@ -1,12 +1,16 @@ // // HttpTestHelpers.swift -// TealiumBraze +// TealiumAppsFlyerTests // // Created by Jonathan Wong on 8/8/19. -// Copyright © 2019 Jonathan Wong. All rights reserved. +// Copyright © 2019 Tealium. All rights reserved. // import Foundation +#if COCOAPODS +#else + import TealiumRemoteCommands +#endif struct RemoteCommandResponsePayload: Codable { var config: [String: String] @@ -31,7 +35,7 @@ class HttpTestHelpers { class func httpRequest(commandId: String, config: [String: Any], payload: [String: Any]) -> URLRequest? { let url = "tealium://\(commandId)?request=" - let remoteCommandrc = ["settings": config, "payload": payload] as [String: Any] + 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) @@ -43,7 +47,7 @@ class HttpTestHelpers { class func httpRequestDescription(commandId: String, config: [String: Any], payload: [String: Any]) -> String? { let url = "tealium://\(commandId)?request=" - let remoteCommandrc = ["settings": config, "payload": payload] as [String: Any] + 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) @@ -53,4 +57,18 @@ class HttpTestHelpers { return nil } + class func createRemoteCommandResponse(type: SimpleCommandType, commandId: String, payload: [String: Any]) -> RemoteCommandResponseProtocol? { + switch type { + case .webview: + let responseDescription = HttpTestHelpers.httpRequestDescription(commandId: commandId, config: [:], payload: payload) + if let description = responseDescription { + return RemoteCommandResponse(urlString: description) + } + case .JSON: + return JSONRemoteCommandResponse(with: payload) + } + print("Could not create Remote Command Response description from stubs provided") + return nil + } + } diff --git a/Tests/MockAppsFlyerCommandTracker.swift b/Tests/MockAppsFlyerInstance.swift similarity index 74% rename from Tests/MockAppsFlyerCommandTracker.swift rename to Tests/MockAppsFlyerInstance.swift index 1a87084..8134a5b 100644 --- a/Tests/MockAppsFlyerCommandTracker.swift +++ b/Tests/MockAppsFlyerInstance.swift @@ -1,21 +1,20 @@ // -// MockAppsFlyerCommandRunner.swift -// AppsFlyerRemoteCommandTests +// MockAppsFlyerInstance.swift +// TealiumAppsFlyerTests // // Created by Christina S on 5/30/19. -// Copyright © 2019 Christina. All rights reserved. +// Copyright © 2019 Tealium. All rights reserved. // import Foundation @testable import TealiumAppsFlyer -class MockAppsFlyerCommandTracker: AppsFlyerTrackable { +class MockAppsFlyerInstance: AppsFlyerCommand { var initWithoutConfigCount = 0 var initWithConfigCount = 0 - var trackLaunchCount = 0 - var trackEventCount = 0 - var trackLocationCount = 0 + var logEventCount = 0 + var logLocationCount = 0 var handlePushNotificationCount = 0 var setHostCount = 0 var setUserEmailsCount = 0 @@ -37,16 +36,12 @@ class MockAppsFlyerCommandTracker: AppsFlyerTrackable { } } - func trackLaunch() { - trackLaunchCount += 1 + func logEvent(_ eventName: String, values: [String : Any]) { + logEventCount += 1 } - func trackEvent(_ eventName: String, values: [String : Any]) { - trackEventCount += 1 - } - - func trackLocation(longitude: Double, latitude: Double) { - trackLocationCount += 1 + func logLocation(longitude: Double, latitude: Double) { + logLocationCount += 1 } func handlePushNofification(payload: [String : Any]?) {