Skip to content

Commit

Permalink
added protocols
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladimir Espinola committed Jun 6, 2024
1 parent 32d41cc commit 7ddb709
Show file tree
Hide file tree
Showing 17 changed files with 164 additions and 96 deletions.
10 changes: 2 additions & 8 deletions Sources/Internal/API/ATTNAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,20 @@ final class ATTNAPI {
}

private var urlSession: URLSession
private var priceFormatter: NumberFormatter
private var domain: String
private var cachedGeoAdjustedDomain: String?

// TODO REVISIT remove later
static var userAgentBuilder: ATTNUserAgentBuilder.Type = ATTNUserAgentBuilder.self
private var userAgentBuilder: ATTNUserAgentBuilderProtocol = ATTNUserAgentBuilder()

init(domain: String) {
self.urlSession = URLSession.build(withUserAgent: ATTNAPI.userAgentBuilder.buildUserAgent())
self.urlSession = URLSession.build(withUserAgent: userAgentBuilder.buildUserAgent())
self.domain = domain
self.priceFormatter = NumberFormatter()
self.priceFormatter.minimumFractionDigits = 2
self.cachedGeoAdjustedDomain = nil
}

init(domain: String, urlSession: URLSession) {
self.urlSession = urlSession
self.domain = domain
self.priceFormatter = NumberFormatter()
self.priceFormatter.minimumFractionDigits = 2
self.cachedGeoAdjustedDomain = nil
}

Expand Down
82 changes: 59 additions & 23 deletions Sources/Internal/ATTNAppInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,82 @@
import Foundation
import UIKit

open class ATTNAppInfo {
open class func getAppBuild() -> String {
Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String ?? ""
protocol ATTNAppInfoProtocol {
func getAppBuild() -> String
func getAppVersion() -> String
func getAppName() -> String
func getAppId() -> String
func getDeviceModelName() -> String
func getDevicePlatform() -> String
func getDeviceOsVersion() -> String
func getSdkName() -> String
func getSdkVersion() -> String
}

extension ATTNAppInfoProtocol {
func getFormattedAppName() -> String {
getAppName().replacingOccurrences(of: " ", with: "-")
}
}

open class func getAppVersion() -> String {
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""
struct ATTNAppInfo: ATTNAppInfoProtocol {
private enum Constants {
static var sdkName: String { "attentive-ios-sdk" }
}

open class func getAppName() -> String {
Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? ""
private enum BundleConstants {
static var bundleVersion: String { "CFBundleVersion" }
static var bundleShortVersion: String { "CFBundleShortVersionString" }
static var bundleName: String { "CFBundleName" }
}

open class func getAppId() -> String {
Bundle.main.bundleIdentifier ?? ""
private var bundle: Bundle
private var uiDevice: UIDevice
private var processInfo: ProcessInfo

init(
bundle: Bundle = Bundle.main,
uiDevice: UIDevice = UIDevice.current,
processInfo: ProcessInfo = ProcessInfo.processInfo
) {
self.bundle = bundle
self.uiDevice = uiDevice
self.processInfo = processInfo
}

open class func getDeviceModelName() -> String {
UIDevice.current.model
func getAppBuild() -> String {
bundle.object(forInfoDictionaryKey: BundleConstants.bundleVersion) as? String ?? ""
}

open class func getDevicePlatform() -> String {
UIDevice.current.systemName
func getAppVersion() -> String {
bundle.object(forInfoDictionaryKey: BundleConstants.bundleShortVersion) as? String ?? ""
}

open class func getDeviceOsVersion() -> String {
ProcessInfo.processInfo.operatingSystemVersionString
func getAppName() -> String {
bundle.object(forInfoDictionaryKey: BundleConstants.bundleName) as? String ?? ""
}

open class func getSdkName() -> String {
"attentive-ios-sdk"
func getAppId() -> String {
bundle.bundleIdentifier ?? ""
}

open class func getSdkVersion() -> String {
ATTNConstants.sdkVersion
func getDeviceModelName() -> String {
uiDevice.model
}
}

public extension ATTNAppInfo {
static func getFormattedAppName() -> String {
getAppName().replacingOccurrences(of: " ", with: "-")
func getDevicePlatform() -> String {
uiDevice.systemName
}

func getDeviceOsVersion() -> String {
processInfo.operatingSystemVersionString
}

func getSdkName() -> String {
Constants.sdkName
}

func getSdkVersion() -> String {
ATTNConstants.sdkVersion
}
}
24 changes: 19 additions & 5 deletions Sources/Internal/ATTNCreativeUrlFormatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,28 @@

import Foundation

struct ATTNCreativeUrlFormatter {
protocol ATTNCreativeUrlFormatterProtocol {
func buildCompanyCreativeUrl(
forDomain domain: String,
mode: String,
userIdentity: ATTNUserIdentity
) -> String
}

struct ATTNCreativeUrlFormatter: ATTNCreativeUrlFormatterProtocol {
private enum Constants {
static var scheme: String { "https" }
static var host: String { "creatives.attn.tv" }
static var path: String { "/mobile-apps/index.html" }
}

static func buildCompanyCreativeUrl(
private let appInfo: ATTNAppInfoProtocol

init(appInfo: ATTNAppInfoProtocol = ATTNAppInfo()) {
self.appInfo = appInfo
}

func buildCompanyCreativeUrl(
forDomain domain: String,
mode: String,
userIdentity: ATTNUserIdentity
Expand Down Expand Up @@ -59,8 +73,8 @@ struct ATTNCreativeUrlFormatter {
}

// Add SDK info just for analytics purposes
queryItems.append(URLQueryItem(name: "sdkVersion", value: ATTNAppInfo.getSdkVersion()))
queryItems.append(URLQueryItem(name: "sdkName", value: ATTNAppInfo.getSdkName()))
queryItems.append(URLQueryItem(name: "sdkVersion", value: appInfo.getSdkVersion()))
queryItems.append(URLQueryItem(name: "sdkName", value: appInfo.getSdkName()))

components.queryItems = queryItems

Expand All @@ -69,7 +83,7 @@ struct ATTNCreativeUrlFormatter {
}

fileprivate extension ATTNCreativeUrlFormatter {
static func getCustomIdentifiersJson(userIdentity: ATTNUserIdentity) -> String? {
func getCustomIdentifiersJson(userIdentity: ATTNUserIdentity) -> String? {
do {
guard let customIdentifiers = userIdentity.identifiers[ATTNIdentifierType.customIdentifiers] else { return nil }
let jsonData = try JSONSerialization.data(withJSONObject: customIdentifiers, options: [])
Expand Down
10 changes: 8 additions & 2 deletions Sources/Internal/ATTNPersistentStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@

import Foundation

struct ATTNPersistentStorage {
protocol ATTNPersistentStorageProtocol {
func save(_ value: AnyObject, forKey key: String)
func readString(forKey key: String) -> String?
func delete(forKey key: String)
}

struct ATTNPersistentStorage: ATTNPersistentStorageProtocol {
private enum Constants {
static var storagePrefix: String { "com.attentive.iossdk.PERSISTENT_STORAGE" }
}

func save(_ value: NSObject, forKey key: String) {
func save(_ value: AnyObject, forKey key: String) {
UserDefaults.standard.setValue(value, forKey: getPrefixedKey(key))
}

Expand Down
13 changes: 9 additions & 4 deletions Sources/Internal/ATTNUserAgentBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@

import Foundation

open class ATTNUserAgentBuilder {
protocol ATTNUserAgentBuilderProtocol {
func buildUserAgent() -> String
}

class ATTNUserAgentBuilder: ATTNUserAgentBuilderProtocol {
private var appInfo: ATTNAppInfoProtocol

open class func buildUserAgent() -> String {
buildUserAgent(appInfo: ATTNAppInfo.self)
init(appInfo: ATTNAppInfoProtocol = ATTNAppInfo()) {
self.appInfo = appInfo
}

static func buildUserAgent(appInfo: ATTNAppInfo.Type) -> String {
func buildUserAgent() -> String {
// We replace the spaces with dashes for the app name because spaces in a User-Agent represent a new "product", so app names that have spaces are harder to parse if we don't replace spaces with dashes
String(
format: "%@/%@.%@ (%@; %@ %@) %@/%@",
Expand Down
6 changes: 3 additions & 3 deletions Sources/Internal/ATTNVisitorService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ struct ATTNVisitorService {
static var visitorIdKey: String { "visitorId" }
}

private let persistentStorage: ATTNPersistentStorage
private let persistentStorage: ATTNPersistentStorageProtocol

init() {
self.persistentStorage = .init()
init(persistentStorage: ATTNPersistentStorageProtocol = ATTNPersistentStorage()) {
self.persistentStorage = persistentStorage
}

func getVisitorId() -> String {
Expand Down
5 changes: 2 additions & 3 deletions Sources/Public/ATTNCreativeTriggerStatus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@

import Foundation

// Status passed to ATTNCreativeTriggerCompletionHandler when the creative is opened successfully
@objc
public class ATTNCreativeTriggerStatus: NSObject {
/// Status passed to ATTNCreativeTriggerCompletionHandler when the creative is opened successfully
@objc public class ATTNCreativeTriggerStatus: NSObject {
@objc public static let opened = "CREATIVE_TRIGGER_STATUS_OPENED"
@objc public static let closed = "CREATIVE_TRIGGER_STATUS_CLOSED"
@objc public static let notOpened = "CREATIVE_TRIGGER_STATUS_NOT_OPENED"
Expand Down
13 changes: 8 additions & 5 deletions Sources/Public/ATTNEventTracker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,35 @@

import Foundation

//@objc(ATTNEventTracker)
@objc(ATTNEventTracker)
public final class ATTNEventTracker: NSObject {
private static var _sharedInstance: ATTNEventTracker?
private let sdk: ATTNSDK

// @objc(initWithSdk:)
@objc(initWithSdk:)
public init(sdk: ATTNSDK) {
self.sdk = sdk
}

// @objc(setupWithSdk:)
@objc(setupWithSdk:)
public static func setup(with sdk: ATTNSDK) {
_sharedInstance = ATTNEventTracker(sdk: sdk)
}

// @objc(recordEvent:)
@objc(recordEvent:)
public func record(event: ATTNEvent) {
sdk.send(event: event)
}

// @objc
@objc
public static func sharedInstance() -> ATTNEventTracker? {
assert(_sharedInstance != nil, "ATTNEventTracker must be setup before being used")
return _sharedInstance
}
}

// MARK: Internal Helpers
extension ATTNEventTracker {
static func destroy() {
_sharedInstance = nil
}
Expand Down
1 change: 1 addition & 0 deletions Sources/Public/ATTNIdentifierType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Foundation
@objc public static let customIdentifiers = "customIdentifiers"
}

// MARK: Internal Helpers
extension ATTNIdentifierType {
static var allKeys: [String] = [
clientUserId,
Expand Down
18 changes: 12 additions & 6 deletions Sources/Public/ATTNSDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ public final class ATTNSDK: NSObject {

private var domain: String
private var mode: ATTNSDKMode
private var urlBuilder: ATTNCreativeUrlFormatterProtocol = ATTNCreativeUrlFormatter()

public convenience init(domain: String, mode: ATTNSDKMode) {
self.init(domain: domain, mode: mode.rawValue)
}

@objc(initWithDomain:)
public convenience init(domain: String) {
Expand Down Expand Up @@ -100,7 +105,7 @@ public final class ATTNSDK: NSObject {
}
NSLog("The iOS version is new enough, continuing to show the Attentive creative.")

let creativePageUrl = ATTNCreativeUrlFormatter.buildCompanyCreativeUrl(
let creativePageUrl = urlBuilder.buildCompanyCreativeUrl(
forDomain: domain,
mode: mode.rawValue,
userIdentity: userIdentity
Expand Down Expand Up @@ -253,13 +258,14 @@ extension ATTNSDK: WKNavigationDelegate {
}
}

// TODO: REVISIT
// MARK: Internal Helpers
extension ATTNSDK {
func getApi() -> ATTNAPI { api }

func getUserIdentity() -> ATTNUserIdentity { userIdentity }

func send(event: ATTNEvent) {
api.send(event: event, userIdentity: userIdentity)
}

convenience init(domain: String, mode: ATTNSDKMode, urlBuilder: ATTNCreativeUrlFormatterProtocol) {
self.init(domain: domain, mode: mode)
self.urlBuilder = urlBuilder
}
}
1 change: 0 additions & 1 deletion Sources/Public/ATTNUserIdentity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import Foundation

// TODO: REVISIT create ObjcATTNUserIdentity wrapper
@objc(ATTNUserIdentity)
public final class ATTNUserIdentity: NSObject {
@objc public var identifiers: [String: Any] {
Expand Down
2 changes: 0 additions & 2 deletions Sources/Public/Events/ATTNAddToCartEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@ import Foundation
public final class ATTNAddToCartEvent: NSObject, ATTNEvent {
@objc public let items: [ATTNItem]

// Public initializer
@objc
public init(items: [ATTNItem]) {
self.items = items
super.init()
}

// Private default initializer to prevent its use
private override init() {
fatalError("init() has not been implemented")
}
Expand Down
20 changes: 10 additions & 10 deletions Tests/Doubles/Mocks/ATTNAppInfoMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
import Foundation
@testable import attentive_ios_sdk_framework

class ATTNAppInfoMock: ATTNAppInfo {
override class func getAppBuild() -> String { "appBuildValue" }
override class func getAppVersion() -> String { "appVersionValue" }
override class func getAppName() -> String { "appName Value" }
override class func getAppId() -> String { "appIdValue" }
override class func getDeviceModelName() -> String { "deviceModelNameValue" }
override class func getDevicePlatform() -> String { "devicePlatformValue" }
override class func getDeviceOsVersion() -> String { "deviceOsVersionValue" }
override class func getSdkName() -> String { "sdkNameValue" }
override class func getSdkVersion() -> String { "sdkVersionValue" }
class ATTNAppInfoMock: ATTNAppInfoProtocol {
func getAppBuild() -> String { "appBuildValue" }
func getAppVersion() -> String { "appVersionValue" }
func getAppName() -> String { "appName Value" }
func getAppId() -> String { "appIdValue" }
func getDeviceModelName() -> String { "deviceModelNameValue" }
func getDevicePlatform() -> String { "devicePlatformValue" }
func getDeviceOsVersion() -> String { "deviceOsVersionValue" }
func getSdkName() -> String { "sdkNameValue" }
func getSdkVersion() -> String { "sdkVersionValue" }
}
Loading

0 comments on commit 7ddb709

Please sign in to comment.