vibes-react-native 5.0.0 → 5.0.1-rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/ios/Vibes.swift +2 -3
  2. package/ios/VibesClient.swift +3 -4
  3. package/ios/VibesPluginLogger.swift +2 -5
  4. package/package.json +3 -2
  5. package/vendor/VibesPush/LICENSE +13 -0
  6. package/vendor/VibesPush/Sources/APIDefinition.swift +502 -0
  7. package/vendor/VibesPush/Sources/Actions.swift +24 -0
  8. package/vendor/VibesPush/Sources/AppObserver.swift +137 -0
  9. package/vendor/VibesPush/Sources/AuthTokenBehavior.swift +17 -0
  10. package/vendor/VibesPush/Sources/CombinedLogger.swift +53 -0
  11. package/vendor/VibesPush/Sources/ConsoleLogger.swift +97 -0
  12. package/vendor/VibesPush/Sources/Credential.swift +41 -0
  13. package/vendor/VibesPush/Sources/CredentialManager.swift +24 -0
  14. package/vendor/VibesPush/Sources/Date+iso8601.swift +34 -0
  15. package/vendor/VibesPush/Sources/Date+logPrefix.swift +20 -0
  16. package/vendor/VibesPush/Sources/DeviceToken.swift +15 -0
  17. package/vendor/VibesPush/Sources/DeviceType.swift +143 -0
  18. package/vendor/VibesPush/Sources/Dictionary+merged.swift +11 -0
  19. package/vendor/VibesPush/Sources/Event.swift +83 -0
  20. package/vendor/VibesPush/Sources/EventCollection.swift +36 -0
  21. package/vendor/VibesPush/Sources/EventTracker.swift +39 -0
  22. package/vendor/VibesPush/Sources/FoundationExtensions.swift +16 -0
  23. package/vendor/VibesPush/Sources/GitTag.swift +27 -0
  24. package/vendor/VibesPush/Sources/HTTP/HTTPBehavior.swift +19 -0
  25. package/vendor/VibesPush/Sources/HTTP/HTTPMethod.swift +20 -0
  26. package/vendor/VibesPush/Sources/HTTP/HTTPResource.swift +69 -0
  27. package/vendor/VibesPush/Sources/HTTP/HTTPResourceClient.swift +190 -0
  28. package/vendor/VibesPush/Sources/HTTP/JSONParser.swift +91 -0
  29. package/vendor/VibesPush/Sources/HTTP/Operations/AssociatePersonOperation.swift +56 -0
  30. package/vendor/VibesPush/Sources/HTTP/Operations/BaseOperation.swift +153 -0
  31. package/vendor/VibesPush/Sources/HTTP/Operations/EventOperation.swift +73 -0
  32. package/vendor/VibesPush/Sources/HTTP/Operations/GetGitTagsOperation.swift +61 -0
  33. package/vendor/VibesPush/Sources/HTTP/Operations/GetInboxMessageOperation.swift +59 -0
  34. package/vendor/VibesPush/Sources/HTTP/Operations/GetInboxMessagesOperation.swift +57 -0
  35. package/vendor/VibesPush/Sources/HTTP/Operations/GetPersonOperation.swift +53 -0
  36. package/vendor/VibesPush/Sources/HTTP/Operations/GetVibesAppInfoOperation.swift +45 -0
  37. package/vendor/VibesPush/Sources/HTTP/Operations/MigrationCallbackOperation.swift +45 -0
  38. package/vendor/VibesPush/Sources/HTTP/Operations/RegisterDeviceOperation.swift +66 -0
  39. package/vendor/VibesPush/Sources/HTTP/Operations/RegisterPushOperation.swift +73 -0
  40. package/vendor/VibesPush/Sources/HTTP/Operations/TrackProductActionOperation.swift +75 -0
  41. package/vendor/VibesPush/Sources/HTTP/Operations/TrackPurchaseActionOperation.swift +81 -0
  42. package/vendor/VibesPush/Sources/HTTP/Operations/UnregisterDeviceOperation.swift +64 -0
  43. package/vendor/VibesPush/Sources/HTTP/Operations/UnregisterPushOperation.swift +72 -0
  44. package/vendor/VibesPush/Sources/HTTP/Operations/UpdateDeviceOperationPatch.swift +57 -0
  45. package/vendor/VibesPush/Sources/HTTP/Operations/UpdateDeviceOperationPut.swift +59 -0
  46. package/vendor/VibesPush/Sources/HTTP/Operations/UpdateMessageOperation.swift +50 -0
  47. package/vendor/VibesPush/Sources/HTTP/Operations/VibesQueueOperation.swift +76 -0
  48. package/vendor/VibesPush/Sources/HTTP/ResourceResult.swift +38 -0
  49. package/vendor/VibesPush/Sources/HTTPURLResponse+cURL.swift +16 -0
  50. package/vendor/VibesPush/Sources/InboxMessage.swift +219 -0
  51. package/vendor/VibesPush/Sources/Info.plist +26 -0
  52. package/vendor/VibesPush/Sources/InputStream+readToString.swift +19 -0
  53. package/vendor/VibesPush/Sources/KeychainStorage.swift +64 -0
  54. package/vendor/VibesPush/Sources/LocalObject.swift +25 -0
  55. package/vendor/VibesPush/Sources/LocalStorageKeys.swift +19 -0
  56. package/vendor/VibesPush/Sources/LocalStorageType.swift +47 -0
  57. package/vendor/VibesPush/Sources/LocalValue.swift +67 -0
  58. package/vendor/VibesPush/Sources/PersistentEventStorage.swift +81 -0
  59. package/vendor/VibesPush/Sources/Person.swift +98 -0
  60. package/vendor/VibesPush/Sources/Product.swift +103 -0
  61. package/vendor/VibesPush/Sources/Purchase.swift +108 -0
  62. package/vendor/VibesPush/Sources/TrackedEventType.swift +48 -0
  63. package/vendor/VibesPush/Sources/URLRequest+cURL.swift +36 -0
  64. package/vendor/VibesPush/Sources/UserDefaultsStorage.swift +32 -0
  65. package/vendor/VibesPush/Sources/Vibes.swift +1069 -0
  66. package/vendor/VibesPush/Sources/VibesAPI.swift +81 -0
  67. package/vendor/VibesPush/Sources/VibesAPIDelegate.swift +41 -0
  68. package/vendor/VibesPush/Sources/VibesAppInfo.swift +77 -0
  69. package/vendor/VibesPush/Sources/VibesConfiguration.swift +108 -0
  70. package/vendor/VibesPush/Sources/VibesLogger.swift +65 -0
  71. package/vendor/VibesPush/Sources/VibesResult.swift +78 -0
  72. package/vibes-react-native.podspec +6 -2
@@ -0,0 +1,137 @@
1
+ import UIKit
2
+
3
+ extension String {
4
+ func toDictionary() -> [String: Any]? {
5
+ if let data = data(using: .utf8) {
6
+ do {
7
+ return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
8
+ } catch {
9
+ Vibes.shared.configuration.logger?.log(error: error)
10
+ }
11
+ }
12
+ return nil
13
+ }
14
+ }
15
+
16
+ /// Observes app lifecycle events and tracks events.
17
+ class AppObserver: NSObject {
18
+ /// A list of the events that should be tracked
19
+ private let trackedEventTypes: [TrackedEventType]
20
+
21
+ /// The event tracker that should be used to track events (usally a Vibes
22
+ /// instance)
23
+ weak var eventTracker: EventTracker?
24
+
25
+ /// The user info and date of the last notification that was received.[
26
+ var lastNotification: (userInfo: [AnyHashable: Any], timestamp: Date)? {
27
+ didSet {
28
+ if let userInfo = lastNotification?.userInfo, shouldTrackPushReceive() {
29
+ trackPushReceive(with: userInfo)
30
+ }
31
+ }
32
+ }
33
+
34
+ /// The threshold of time between receiving a notification and the app
35
+ /// becoming active that we should consider a "clickthru"
36
+ private let clickthruThreshold: TimeInterval // seconds
37
+
38
+ /// Initialize this object.
39
+ ///
40
+ /// - parameters:
41
+ /// - trackedEventTypes: the type of events that should be tracked
42
+ /// (default: all)
43
+ /// - clickthruThreshold - the threshold of time between receiving a
44
+ /// notification and the app becoming active that we should consider
45
+ /// a "clickthru" (default: 1 second)
46
+ init(trackedEventTypes: [TrackedEventType] = TrackedEventType.all, clickthruThreshold: TimeInterval = 1) {
47
+ self.clickthruThreshold = clickthruThreshold
48
+ self.trackedEventTypes = trackedEventTypes
49
+
50
+ super.init()
51
+
52
+ NotificationCenter.default.addObserver(
53
+ self,
54
+ selector: #selector(applicationDidBecomeActive(_:)),
55
+ name: UIApplication.didBecomeActiveNotification,
56
+ object: nil
57
+ )
58
+ }
59
+
60
+ /// Run on deallocation.
61
+ deinit {
62
+ NotificationCenter.default.removeObserver(self)
63
+ }
64
+
65
+ /// Tracks when the application became active. If there's a push
66
+ /// notification, this fires after it is received by the AppDelegate.
67
+ ///
68
+ /// - parameters:
69
+ /// - the notification fired by iOS
70
+ @objc func applicationDidBecomeActive(_ notification: Notification) {
71
+ if trackedEventTypes.contains(.launch) {
72
+ trackLaunch()
73
+ }
74
+
75
+ if let (userInfo, _) = lastNotification, shouldTrackClickThru() {
76
+ trackClickthru(with: userInfo)
77
+ }
78
+ lastNotification = nil
79
+ }
80
+
81
+ /// Determines if a clickthru should be tracked, based on the user vibes configuration
82
+ private func shouldTrackClickThru() -> Bool {
83
+ return trackedEventTypes.contains(.clickthru)
84
+ }
85
+
86
+ /// Determines if a .pushReceive should be tracked, based on the user vibes configuration
87
+ private func shouldTrackPushReceive() -> Bool {
88
+ return trackedEventTypes.contains(.pushReceive)
89
+ }
90
+
91
+ /// Tracks a launch event.
92
+ private func trackLaunch() {
93
+ let event = Event(eventType: .launch, properties: [:])
94
+ eventTracker?.track(event: event)
95
+ }
96
+
97
+ func eventProps(with userInfo: [AnyHashable: Any]) -> [AnyHashable: Any] {
98
+ var properties: [AnyHashable: Any] = [:]
99
+
100
+ if let messageUniqueId = userInfo["message_uid"] as? String {
101
+ properties["message_uid"] = messageUniqueId
102
+ }
103
+
104
+ if let clientAppData = userInfo["client_app_data"] as? [AnyHashable: Any] {
105
+ if let activityType = clientAppData["activity_type"] as? String {
106
+ properties["activity_type"] = activityType
107
+ }
108
+
109
+ if let activityUid = clientAppData["activity_uid"] as? String {
110
+ properties["activity_uid"] = activityUid
111
+ }
112
+ }
113
+
114
+ return properties
115
+
116
+ }
117
+
118
+ /// Tracks a clickthru event.
119
+ ///
120
+ /// - parameters:
121
+ /// - userInfo: the details from the push notification to track
122
+ private func trackClickthru(with userInfo: [AnyHashable: Any]) {
123
+ var properties: [AnyHashable: Any] = eventProps(with: userInfo)
124
+ let event = Event(eventType: .clickthru, properties: properties)
125
+ eventTracker?.track(event: event)
126
+ }
127
+
128
+ /// Tracks a push_receive event.
129
+ ///
130
+ /// - parameters:
131
+ /// - userInfo: the details from the push notification to track
132
+ private func trackPushReceive(with userInfo: [AnyHashable: Any]) {
133
+ var properties: [AnyHashable: Any] = eventProps(with: userInfo)
134
+ let event = Event(eventType: .pushReceive, properties: properties)
135
+ eventTracker?.track(event: event)
136
+ }
137
+ }
@@ -0,0 +1,17 @@
1
+ import Foundation
2
+ /// A behavior for adding the necessary authentication token for requests to the
3
+ /// Vibes API.
4
+ struct AuthTokenBehavior: HTTPBehavior {
5
+ /// An authentication token to send in an request header.
6
+ let token: String?
7
+
8
+ /// Modifies the request by adding an `Authorization` header.
9
+ ///
10
+ /// - parameters:
11
+ /// - request: the request to modify
12
+ func modifyRequest(request: inout URLRequest) {
13
+ if let token = self.token {
14
+ request.setValue("MobileAppToken \(token)", forHTTPHeaderField: "Authorization")
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,53 @@
1
+ //
2
+ // CombinedLogger.swift
3
+ // VibesPush-iOS
4
+ //
5
+ // Created by Moin' Victor on 20/08/2020.
6
+ // Copyright © 2020 Vibes. All rights reserved.
7
+ //
8
+
9
+ import Foundation
10
+
11
+ /// A Logger that writes to the `ConsoleLogger` if enabled, as well as to any custom Logger provider to `VibesConfigration` during init.
12
+ @objc public class CombinedLogger: NSObject, VibesLogger {
13
+ /// The custom logger provided in `VibesConfigration` during init.
14
+ public var customLogger: VibesLogger?
15
+
16
+ /// The console logger to use
17
+ public var consoleLogger: ConsoleLogger? {
18
+ return VibesConfiguration.consoleLogger
19
+ }
20
+
21
+ /// Initialize this object.
22
+ ///
23
+ /// - Parameters:
24
+ /// - customLogger: The custom logger provided in `VibesConfigration` during init.
25
+ init(customLogger: VibesLogger?) {
26
+ super.init()
27
+ self.customLogger = customLogger
28
+ }
29
+
30
+ /// Logs a message to the console if the `logObject.level` matches or is above the configured log `level`
31
+ ///
32
+ /// - Parameters:
33
+ /// - logObject: The Log object with log `level` and specified log `message`.
34
+ public func log(_ logObject: LogObject) {
35
+ consoleLogger?.log(logObject)
36
+ customLogger?.log(logObject)
37
+ }
38
+
39
+ public func log(request: URLRequest) {
40
+ consoleLogger?.log(request: request)
41
+ customLogger?.log(request: request)
42
+ }
43
+
44
+ public func log(response: URLResponse, data: Data?) {
45
+ consoleLogger?.log(response: response, data: data)
46
+ customLogger?.log(response: response, data: data)
47
+ }
48
+
49
+ public func log(error: Error) {
50
+ consoleLogger?.log(error: error)
51
+ customLogger?.log(error: error)
52
+ }
53
+ }
@@ -0,0 +1,97 @@
1
+ import Foundation
2
+
3
+ /// A simple Logger that writes to the Xcode console.
4
+ @objc public class ConsoleLogger: NSObject, VibesLogger {
5
+ /// Prefix for logging SDK initialization
6
+ static let versionInfoLogPrefix = "Initializing Vibes SDK v"
7
+
8
+ /// The level for this logger
9
+ private var level: LogLevel
10
+
11
+ /// Initialize this object.
12
+ ///
13
+ /// - Parameters:
14
+ /// - level: the level for this logger
15
+ init(level: LogLevel = .verbose) {
16
+ self.level = level
17
+ super.init()
18
+ }
19
+
20
+ /// Logs a message to the console if the `logObject.level` matches or is above the configured log `level`
21
+ ///
22
+ /// - Parameters:
23
+ /// - logObject: The Log object with log `level` and specified log `message`.
24
+ public func log(_ logObject: LogObject) {
25
+ if logObject.level.rawValue >= level.rawValue {
26
+ printLogMessage(logObject.level, message: logObject.message)
27
+ }
28
+ }
29
+
30
+ /// Logs an HTTP request to the console.
31
+ ///
32
+ /// - Parameters:
33
+ /// - request: the HTTP request to log
34
+ public func log(request: URLRequest) {
35
+ switch level {
36
+ case .verbose:
37
+ log(LogObject(.verbose, message: "Request: \(request.toString())"))
38
+ default:
39
+ break
40
+ }
41
+ }
42
+
43
+ /// Logs an HTTP response with its accompanying data to the console.
44
+ ///
45
+ /// - Parameters:
46
+ /// - response: the HTTP response to log
47
+ /// - data: the data received, if any
48
+ public func log(response: URLResponse, data: Data? = nil) {
49
+ guard let response = response as? HTTPURLResponse else { return }
50
+
51
+ switch level {
52
+ case .verbose:
53
+ log(LogObject(.verbose, message: "Response: \(response.responseCodeDescription)"))
54
+ log(data: data)
55
+ default:
56
+ break
57
+ }
58
+ }
59
+
60
+ /// Logs an error the console.
61
+ ///
62
+ /// - Parameters:
63
+ /// - error: the error that occurred
64
+ public func log(error: Error) {
65
+ log(LogObject(.error, message: "Error: \(error.localizedDescription)"))
66
+ }
67
+
68
+ /// Logs data to the console, if it exists.
69
+ ///
70
+ /// - parameters:
71
+ /// - data: the Data of the HTTP response
72
+ private func log(data: Data?) {
73
+ guard let data = data else { return }
74
+
75
+ do {
76
+ let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
77
+ let pretty = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
78
+
79
+ if let string = NSString(data: pretty, encoding: String.Encoding.utf8.rawValue) {
80
+ log(LogObject(.verbose, message: "JSON: \(string)"))
81
+ }
82
+ } catch {
83
+ if let string = NSString(data: data, encoding: String.Encoding.utf8.rawValue) {
84
+ log(LogObject(.verbose, message: "Data: \(string)"))
85
+ }
86
+ }
87
+ }
88
+
89
+ /// Prints out the log message with template `[TIMESTAMP] VibesPush/[logLevel]: <MSG>`
90
+ ///
91
+ /// - Parameters:
92
+ /// - msgLogLevel: The log level for the message
93
+ /// - message: The message to print on the log
94
+ func printLogMessage(_ msgLogLevel: LogLevel = .verbose, message: String) {
95
+ print("\(Date.logPrefix) VibesPush/\(msgLogLevel.logPrefix): \(message)")
96
+ }
97
+ }
@@ -0,0 +1,41 @@
1
+ /// A value object to represent the credentials needed to interact with the
2
+ /// Vibes API.
3
+ public struct VibesCredential {
4
+ /// A unique identifier for the device, provided by Vibes when registering.
5
+ public let deviceId: String
6
+
7
+ /// A unique, transient token for the device. The combination of `deviceId`
8
+ /// and `authToken` is used to authenticate most calls in the `VibesAPI`.
9
+ public let authToken: String
10
+ }
11
+
12
+ extension VibesCredential: JSONDecodable {
13
+ init?(json: VibesJSONDictionary) {
14
+ guard let device = json["device"] as? VibesJSONDictionary,
15
+ let deviceId = device["vibes_device_id"] as? String,
16
+ let authToken = json["auth_token"] as? String else { return nil }
17
+
18
+ self.deviceId = deviceId
19
+ self.authToken = authToken
20
+ }
21
+ }
22
+
23
+ extension VibesCredential: Equatable {
24
+ public static func == (lhs: VibesCredential, rhs: VibesCredential) -> Bool {
25
+ return lhs.deviceId == rhs.deviceId && lhs.authToken == rhs.authToken
26
+ }
27
+ }
28
+
29
+ extension VibesCredential: LocalObjectType {
30
+ public var attributes: [String: Any] {
31
+ return ["id": deviceId, "token": authToken]
32
+ }
33
+
34
+ public init?(attributes: [String: Any]) {
35
+ guard let id = attributes["id"] as? String,
36
+ let token = attributes["token"] as? String else { return nil }
37
+
38
+ self.deviceId = id
39
+ self.authToken = token
40
+ }
41
+ }
@@ -0,0 +1,24 @@
1
+ /// Handles storing credentials, keeping track of the current Credential, etc.
2
+ class CredentialManager {
3
+ /// An object for storing data in some kind of local storage.
4
+ private let storage: LocalStorageType
5
+
6
+ /// The currently-active Credential
7
+ var currentCredential: VibesCredential? {
8
+ get {
9
+ return storage.get(LocalStorageKeys.currentCredential)
10
+ }
11
+
12
+ set {
13
+ storage.set(newValue, for: LocalStorageKeys.currentCredential)
14
+ }
15
+ }
16
+
17
+ /// Initialize this object.
18
+ ///
19
+ /// - parameters:
20
+ /// - storage: an object that allows storing data locally
21
+ init(storage: LocalStorageType) {
22
+ self.storage = storage
23
+ }
24
+ }
@@ -0,0 +1,34 @@
1
+ import Foundation
2
+
3
+ public extension Formatter {
4
+ /// A date formatter for generating ISO8601-compatible timestamp strings.
5
+ static let iso8601: DateFormatter = {
6
+ let formatter = DateFormatter()
7
+
8
+ formatter.calendar = Calendar(identifier: .iso8601)
9
+ formatter.locale = Locale(identifier: "en_US_POSIX")
10
+ formatter.timeZone = TimeZone(secondsFromGMT: 0)
11
+ formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
12
+
13
+ return formatter
14
+ }()
15
+ }
16
+
17
+ public extension Date {
18
+ /// An ISO8601-compatible timestamp string for this Date object.
19
+ var iso8601: String {
20
+ return Formatter.iso8601.string(from: self)
21
+ }
22
+
23
+ var iso8601WithUpdatingTimezone: String {
24
+ let formatter = Formatter.iso8601
25
+ formatter.timeZone = TimeZone.autoupdatingCurrent
26
+ return formatter.string(from: self)
27
+ }
28
+ }
29
+
30
+ public extension String {
31
+ var iso8601: Date? {
32
+ return Formatter.iso8601.date(from: self)
33
+ }
34
+ }
@@ -0,0 +1,20 @@
1
+ //
2
+ // Date+logPrefix.swift
3
+ // VibesPush
4
+ //
5
+ // Created by Moin' Victor on 25/08/2020.
6
+ // Copyright © 2020 Vibes. All rights reserved.
7
+ //
8
+
9
+ import Foundation
10
+
11
+ // MARK: - Date + log prefix
12
+
13
+ extension Date {
14
+ public static var logPrefix: String {
15
+ let dateFormatter = DateFormatter()
16
+ dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
17
+ let nowString = dateFormatter.string(from: Date())
18
+ return "[\(nowString)]"
19
+ }
20
+ }
@@ -0,0 +1,15 @@
1
+ /// A small data object to hold a push token received from Apple. This provides
2
+ /// a convenient place to add our JSON encoding code.
3
+ struct DeviceToken {
4
+ let token: String
5
+ }
6
+
7
+ extension DeviceToken: JSONEncodable {
8
+ func encodeJSON() -> VibesJSONDictionary {
9
+ return [
10
+ "device": [
11
+ "push_token": token,
12
+ ] as AnyObject,
13
+ ]
14
+ }
15
+ }
@@ -0,0 +1,143 @@
1
+ import UIKit
2
+
3
+ /// A protocol that indicates the required interface for being considered a
4
+ /// `Device` in the Vibes system.
5
+ protocol DeviceType: JSONEncodable {
6
+ /// The operating system of this device, e.g. iOS
7
+ var systemName: String { get }
8
+
9
+ /// The operating system version of this device, e.g. "10.3.1"
10
+ var systemVersion: String { get }
11
+
12
+ /// The hardware make of this device, e.g. "Apple"
13
+ var hardwareMake: String { get }
14
+
15
+ /// The hardware model of this device, e.g. "iPhone9,1"
16
+ var hardwareModel: String { get }
17
+
18
+ /// The locale for this device, e.g. "en_US"
19
+ var localeIdentifier: String { get }
20
+
21
+ /// The timezone for this device, e.g. "America/Chicago"
22
+ var timeZoneIdentifier: String { get }
23
+
24
+ /// The version of the Vibes SDK installed on this device, e.g. "1.0.1"
25
+ var sdkVersion: String { get }
26
+
27
+ /// The version of the app installed on this device, e.g. "2.0.0"
28
+ var appVersion: String { get }
29
+
30
+ /// A unique advertising identifier for this device, e.g.
31
+ /// "E621E1F8-C36C-495A-93FC-0C247A3E6E5F"
32
+ var advertisingIdentifier: String? { get }
33
+
34
+ /// User location if provided
35
+ var location: (lat: Double, long: Double)? { get }
36
+ }
37
+
38
+ /// A simple data object to allow us to send serialized Device information to
39
+ /// Vibes.
40
+ struct Device {
41
+
42
+ /// A unique advertising identifier for this device, e.g.
43
+ /// "E621E1F8-C36C-495A-93FC-0C247A3E6E5F"
44
+ let advertisingIdentifier: String?
45
+
46
+ /// User location :-(
47
+ var location: (lat: Double, long: Double)?
48
+
49
+ /// Initialize this object.
50
+ ///
51
+ /// - parameters:
52
+ /// - advertisingIdentifier: AdSupport.AdvertisingIdentifier, A unique advertising
53
+ /// identifier for this device
54
+ init(advertisingIdentifier: String?, location: (lat: Double, long: Double)? = nil) {
55
+ // check if Ad tracking has been limited by the app's user.
56
+ // https://developer.apple.com/documentation/adsupport/asidentifiermanager
57
+ // Sad day: elvis operator '?:' doesn't work in swift.
58
+ if advertisingIdentifier == "00000000-0000-0000-0000-000000000000" || advertisingIdentifier == "" {
59
+ self.advertisingIdentifier = nil
60
+ } else {
61
+ self.advertisingIdentifier = advertisingIdentifier
62
+ }
63
+ if let location = location {
64
+ self.location = location
65
+ }
66
+ }
67
+ }
68
+
69
+ extension Device: DeviceType {
70
+
71
+ var systemName: String {
72
+ return "iOS"
73
+ }
74
+
75
+ var systemVersion: String {
76
+ return UIDevice.current.systemVersion
77
+ }
78
+
79
+ var identifierForVendor: UUID? {
80
+ return UIDevice.current.identifierForVendor
81
+ }
82
+
83
+ var localeIdentifier: String {
84
+ return Locale.current.identifier
85
+ }
86
+
87
+ var timeZoneIdentifier: String {
88
+ return NSTimeZone.local.identifier
89
+ }
90
+
91
+ var hardwareMake: String {
92
+ return "Apple"
93
+ }
94
+
95
+ var hardwareModel: String {
96
+ var systemInfo = utsname()
97
+ uname(&systemInfo)
98
+
99
+ let modelCode = withUnsafePointer(to: &systemInfo.machine) {
100
+ $0.withMemoryRebound(to: CChar.self, capacity: 1) { ptr in
101
+ String.init(validatingUTF8: ptr)
102
+ }
103
+ }
104
+
105
+ return modelCode ?? "Unknown"
106
+ }
107
+
108
+ var sdkVersion: String {
109
+ return Vibes.SDK_VERSION
110
+ }
111
+
112
+ var appVersion: String {
113
+ return Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
114
+ }
115
+ }
116
+
117
+ extension DeviceType {
118
+ func encodeJSON() -> VibesJSONDictionary {
119
+ var locationDictionary: VibesJSONDictionary?
120
+ if let loc = location {
121
+ locationDictionary = [
122
+ "latitude": loc.lat as AnyObject,
123
+ "longitude": loc.long as AnyObject,
124
+ ]
125
+ }
126
+ let dictionary: VibesJSONDictionary = [
127
+ "device": [
128
+ "os": systemName,
129
+ "os_version": systemVersion,
130
+ "sdk_version": sdkVersion,
131
+ "app_version": appVersion,
132
+ "hardware_make": hardwareMake,
133
+ "hardware_model": hardwareModel,
134
+ "advertising_id": advertisingIdentifier as Any,
135
+ "locale": localeIdentifier,
136
+ "timezone": timeZoneIdentifier,
137
+ "location": locationDictionary as AnyObject,
138
+ ] as AnyObject,
139
+ ]
140
+
141
+ return dictionary
142
+ }
143
+ }
@@ -0,0 +1,11 @@
1
+ extension Dictionary {
2
+ /// Merges a dictionary into this one.
3
+ ///
4
+ /// - parameters:
5
+ /// - dictionary: the Dictionary to merge in
6
+ func merged(with dictionary: [Key: Value]) -> [Key: Value] {
7
+ var copy = self
8
+ dictionary.forEach { copy.updateValue($1, forKey: $0) }
9
+ return copy
10
+ }
11
+ }
@@ -0,0 +1,83 @@
1
+ import Foundation
2
+
3
+ /// A data object to represent an Event to send to Vibes.
4
+ struct Event {
5
+ /// The type of the event
6
+ fileprivate let eventType: TrackedEventType
7
+
8
+ /// Event unique id (string representation)
9
+ let uuid: String
10
+
11
+ /// The time the Event occurred
12
+ let timestamp: Date
13
+
14
+ /// A set of arbitrary key/values to send along with the event
15
+ let properties: [AnyHashable: Any]
16
+
17
+ /// A convenience property for retrieving the type of the event as a String.
18
+ var type: String {
19
+ return eventType.name()
20
+ }
21
+
22
+ /// Checks if this event of of type `launch`
23
+ var isLaunchEvent: Bool {
24
+ return self.type == TrackedEventType.launch.name()
25
+ }
26
+
27
+ /// Initialize this object.
28
+ ///
29
+ /// - parameters:
30
+ /// - eventType: the type of the event
31
+ /// - properties: a set of arbitrary key/values to send along with the event
32
+ /// - timestamp: the time the Event occurred
33
+ init(eventType: TrackedEventType, properties: [AnyHashable: Any], timestamp: Date = Date()) {
34
+ uuid = UUID().uuidString
35
+ self.eventType = eventType
36
+ self.properties = properties
37
+ self.timestamp = timestamp
38
+ }
39
+ }
40
+
41
+ extension Event: Equatable {
42
+ static func == (lhs: Event, rhs: Event) -> Bool {
43
+ return lhs.uuid == rhs.uuid &&
44
+ lhs.type == rhs.type &&
45
+ lhs.timestamp == rhs.timestamp
46
+ }
47
+ }
48
+
49
+ extension Event: JSONEncodable {
50
+ func encodeJSON() -> VibesJSONDictionary {
51
+ return [
52
+ "uuid": uuid,
53
+ "type": type,
54
+ "timestamp": timestamp.iso8601,
55
+ "attributes": properties,
56
+ ] as VibesJSONDictionary
57
+ }
58
+ }
59
+
60
+ extension Event: LocalObjectType {
61
+ var attributes: [String: Any] {
62
+ return [
63
+ "uuid": uuid,
64
+ "type": type,
65
+ "timestamp": timestamp,
66
+ "properties": properties,
67
+ ]
68
+ }
69
+
70
+ init?(attributes: [String: Any]) {
71
+ guard let uuid = attributes["uuid"] as? String,
72
+ let timestamp = attributes["timestamp"] as? Date,
73
+ let properties = attributes["properties"] as? [AnyHashable: Any],
74
+ let type = attributes["type"] as? String else {
75
+ return nil
76
+ }
77
+
78
+ self.uuid = uuid
79
+ self.properties = properties
80
+ self.timestamp = timestamp
81
+ eventType = TrackedEventType.convert(rawValue: type)
82
+ }
83
+ }