├── .gitignore
├── AnalyticsSwift iOS-Info.plist
├── AnalyticsSwift-tvOS-Info.plist
├── AnalyticsSwift.podspec
├── AnalyticsSwift.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ ├── AnalyticsSwift-iOS.xcscheme
│ ├── AnalyticsSwift-tvOS.xcscheme
│ └── AnalyticsSwift.xcscheme
├── AnalyticsSwift
├── AliasMessageBuilder.swift
├── Analytics.swift
├── AnalyticsSwift.h
├── Credentials.swift
├── Executor.swift
├── GroupMessageBuilder.swift
├── IdentifyMessageBuilder.swift
├── Info.plist
├── MessageBuilder.swift
├── ScreenMessageBuilder.swift
├── SerialExecutor.swift
└── TrackMessageBuilder.swift
├── AnalyticsSwiftExample
├── AnalyticsSwiftExample.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── AnalyticsSwiftExample.xcscheme
├── AnalyticsSwiftExample.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── AnalyticsSwiftExample
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── base_small.imageset
│ │ │ ├── Contents.json
│ │ │ └── base_small.jpg
│ │ ├── segment_logo.imageset
│ │ │ ├── Contents.json
│ │ │ └── segment_logo.png
│ │ ├── stack_small.imageset
│ │ │ ├── Contents.json
│ │ │ └── stack_small.jpg
│ │ └── stack_smaller.imageset
│ │ │ ├── Contents.json
│ │ │ └── stack_smaller.jpg
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ ├── PageViewController.swift
│ ├── PrimaryViewController.swift
│ └── SecondaryViewController.swift
├── Podfile
├── Podfile.lock
└── Pods
│ ├── Analytics
│ ├── Analytics
│ │ ├── Classes
│ │ │ ├── Crypto
│ │ │ │ ├── SEGAES256Crypto.h
│ │ │ │ ├── SEGAES256Crypto.m
│ │ │ │ └── SEGCrypto.h
│ │ │ ├── Integrations
│ │ │ │ ├── SEGAliasPayload.h
│ │ │ │ ├── SEGAliasPayload.m
│ │ │ │ ├── SEGGroupPayload.h
│ │ │ │ ├── SEGGroupPayload.m
│ │ │ │ ├── SEGIdentifyPayload.h
│ │ │ │ ├── SEGIdentifyPayload.m
│ │ │ │ ├── SEGIntegration.h
│ │ │ │ ├── SEGIntegrationFactory.h
│ │ │ │ ├── SEGIntegrationsManager.h
│ │ │ │ ├── SEGIntegrationsManager.m
│ │ │ │ ├── SEGPayload.h
│ │ │ │ ├── SEGPayload.m
│ │ │ │ ├── SEGScreenPayload.h
│ │ │ │ ├── SEGScreenPayload.m
│ │ │ │ ├── SEGTrackPayload.h
│ │ │ │ └── SEGTrackPayload.m
│ │ │ ├── Internal
│ │ │ │ ├── NSData+SEGGZIP.h
│ │ │ │ ├── NSData+SEGGZIP.m
│ │ │ │ ├── SEGAnalyticsUtils.h
│ │ │ │ ├── SEGAnalyticsUtils.m
│ │ │ │ ├── SEGFileStorage.h
│ │ │ │ ├── SEGFileStorage.m
│ │ │ │ ├── SEGHTTPClient.h
│ │ │ │ ├── SEGHTTPClient.m
│ │ │ │ ├── SEGSegmentIntegration.h
│ │ │ │ ├── SEGSegmentIntegration.m
│ │ │ │ ├── SEGSegmentIntegrationFactory.h
│ │ │ │ ├── SEGSegmentIntegrationFactory.m
│ │ │ │ ├── SEGStorage.h
│ │ │ │ ├── SEGStoreKitTracker.h
│ │ │ │ ├── SEGStoreKitTracker.m
│ │ │ │ ├── SEGUserDefaultsStorage.h
│ │ │ │ ├── SEGUserDefaultsStorage.m
│ │ │ │ ├── SEGUtils.h
│ │ │ │ ├── SEGUtils.m
│ │ │ │ ├── UIViewController+SEGScreen.h
│ │ │ │ └── UIViewController+SEGScreen.m
│ │ │ ├── Middlewares
│ │ │ │ ├── SEGContext.h
│ │ │ │ ├── SEGContext.m
│ │ │ │ ├── SEGMiddleware.h
│ │ │ │ └── SEGMiddleware.m
│ │ │ ├── SEGAnalytics.h
│ │ │ ├── SEGAnalytics.m
│ │ │ ├── SEGAnalyticsConfiguration.h
│ │ │ ├── SEGAnalyticsConfiguration.m
│ │ │ └── SEGSerializableValue.h
│ │ └── Vendor
│ │ │ ├── SEGReachability.h
│ │ │ └── SEGReachability.m
│ ├── LICENSE
│ └── README.md
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ └── project.pbxproj
│ └── Target Support Files
│ ├── Analytics
│ ├── Analytics-Info.plist
│ ├── Analytics-dummy.m
│ ├── Analytics-prefix.pch
│ ├── Analytics-umbrella.h
│ ├── Analytics.modulemap
│ └── Analytics.xcconfig
│ └── Pods-AnalyticsSwiftExample
│ ├── Pods-AnalyticsSwiftExample-Info.plist
│ ├── Pods-AnalyticsSwiftExample-acknowledgements.markdown
│ ├── Pods-AnalyticsSwiftExample-acknowledgements.plist
│ ├── Pods-AnalyticsSwiftExample-dummy.m
│ ├── Pods-AnalyticsSwiftExample-frameworks.sh
│ ├── Pods-AnalyticsSwiftExample-umbrella.h
│ ├── Pods-AnalyticsSwiftExample.debug.xcconfig
│ ├── Pods-AnalyticsSwiftExample.modulemap
│ └── Pods-AnalyticsSwiftExample.release.xcconfig
├── AnalyticsSwiftTests
├── AnalyticsSwiftTests.swift
├── Info.plist
└── SynchronousExecutor.swift
├── LICENSE.md
├── Makefile
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io
2 |
3 | ### Objective-C ###
4 | # Xcode
5 | #
6 | build/
7 | *.pbxuser
8 | !default.pbxuser
9 | *.mode1v3
10 | !default.mode1v3
11 | *.mode2v3
12 | !default.mode2v3
13 | *.perspectivev3
14 | !default.perspectivev3
15 | xcuserdata
16 | *.xccheckout
17 | *.moved-aside
18 | DerivedData
19 | *.hmap
20 | *.ipa
21 | *.xcuserstate
22 |
23 | # CocoaPods
24 | #
25 | # We recommend against adding the Pods directory to your .gitignore. However
26 | # you should judge for yourself, the pros and cons are mentioned at:
27 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
28 | #
29 | #Pods/
30 |
31 |
32 | ### Swift ###
33 | # Xcode
34 | #
35 | build/
36 | *.pbxuser
37 | !default.pbxuser
38 | *.mode1v3
39 | !default.mode1v3
40 | *.mode2v3
41 | !default.mode2v3
42 | *.perspectivev3
43 | !default.perspectivev3
44 | xcuserdata
45 | *.xccheckout
46 | *.moved-aside
47 | DerivedData
48 | *.hmap
49 | *.ipa
50 | *.xcuserstate
51 |
52 | # CocoaPods
53 | #
54 | # We recommend against adding the Pods directory to your .gitignore. However
55 | # you should judge for yourself, the pros and cons are mentioned at:
56 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
57 | #
58 | # Pods/
59 |
60 | # Carthage
61 | #
62 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
63 | # Carthage/Checkouts
64 |
65 | Carthage/Build
66 |
67 |
68 | ### OSX ###
69 | .DS_Store
70 | .AppleDouble
71 | .LSOverride
72 |
73 | # Icon must end with two \r
74 | Icon
75 |
76 | # Thumbnails
77 | ._*
78 |
79 | # Files that might appear in the root of a volume
80 | .DocumentRevisions-V100
81 | .fseventsd
82 | .Spotlight-V100
83 | .TemporaryItems
84 | .Trashes
85 | .VolumeIcon.icns
86 |
87 | # Directories potentially created on remote AFP share
88 | .AppleDB
89 | .AppleDesktop
90 | Network Trash Folder
91 | Temporary Items
92 | .apdisk
93 |
94 |
--------------------------------------------------------------------------------
/AnalyticsSwift iOS-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2015 Segment. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/AnalyticsSwift-tvOS-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2015 Segment. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/AnalyticsSwift.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 | spec.name = 'AnalyticsSwift'
3 | spec.version = '0.2.0'
4 |
5 | spec.license = { :type => 'MIT' }
6 |
7 | spec.homepage = 'https://github.com/segmentio/analytics-swift'
8 | spec.authors = { 'Segment' => 'friends@segment.com' }
9 | spec.summary = 'The hassle-free way to add analytics to your Swift app.'
10 |
11 | spec.source = { :git => 'https://github.com/segmentio/analytics-swift.git', :tag => spec.version }
12 |
13 | spec.source_files = 'AnalyticsSwift/*.swift'
14 |
15 | spec.ios.deployment_target = '8.0'
16 | spec.osx.deployment_target = '10.9'
17 | spec.tvos.deployment_target = '9.0'
18 |
19 | spec.requires_arc = true
20 | end
21 |
--------------------------------------------------------------------------------
/AnalyticsSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/AnalyticsSwift.xcodeproj/xcshareddata/xcschemes/AnalyticsSwift-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
59 |
65 |
66 |
72 |
73 |
74 |
75 |
77 |
78 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/AnalyticsSwift.xcodeproj/xcshareddata/xcschemes/AnalyticsSwift-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
59 |
65 |
66 |
72 |
73 |
74 |
75 |
77 |
78 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/AnalyticsSwift.xcodeproj/xcshareddata/xcschemes/AnalyticsSwift.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
66 |
67 |
73 |
74 |
75 |
76 |
77 |
78 |
84 |
85 |
91 |
92 |
93 |
94 |
96 |
97 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/AnalyticsSwift/AliasMessageBuilder.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright © 2015 Segment, Inc.
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Foundation
24 |
25 | public class AliasMessageBuilder: MessageBuilder {
26 | private var dictionary: [String: AnyObject] = [:]
27 |
28 | public init(previousId: String) {
29 | dictionary["type"] = "alias" as AnyObject
30 | dictionary["previousId"] = previousId as AnyObject
31 | }
32 |
33 | // Common
34 |
35 | public func userId(_ userId: String) -> AliasMessageBuilder {
36 | dictionary["userId"] = userId as AnyObject
37 | return self
38 | }
39 |
40 | public func anonymousId(_ anonymousId: String) -> AliasMessageBuilder {
41 | dictionary["anonymousId"] = anonymousId as AnyObject
42 | return self
43 | }
44 |
45 | public func context(_ context: [String: AnyObject]) -> AliasMessageBuilder {
46 | dictionary["context"] = context as AnyObject
47 | return self
48 | }
49 |
50 | public func build() -> [String: AnyObject] {
51 | return dictionary
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/AnalyticsSwift/Analytics.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright © 2015 Segment, Inc.
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Foundation
24 |
25 | /**
26 | The entry point into the Analytics for Swift library.
27 | */
28 |
29 | public class Analytics {
30 |
31 | /**
32 | The writeKey for the Segment project this client will upload events to.
33 | */
34 |
35 | private let writeKey: String
36 |
37 | /**
38 | In memory queue of enqueued events.
39 | */
40 |
41 | private var messageQueue: [[String: AnyObject]]
42 |
43 | /**
44 | Executor that handles interactions with the messageQueue. This will also be used to upload events.
45 | */
46 |
47 | private let executor: Executor
48 |
49 | /**
50 | Queue size at which we automatically upload events
51 | */
52 |
53 | private let flushQueueSize = 10
54 |
55 | // MARK: Public interface
56 |
57 | /**
58 | Initializes a new Analytics client with the provided parameters.
59 | - parameter writeKey: Write Key for your Segment project
60 | - returns: A beautiful, brand-new, custom built Analytics client just for you. ❤️
61 | */
62 |
63 | public static func create(writeKey: String) -> Analytics {
64 | let executor = SerialExecutor(name:"com.segment.executor." + writeKey)
65 | return Analytics(writeKey: writeKey, queue: [], executor: executor)
66 | }
67 |
68 | /**
69 | Initializes a new Analytics client with the provided parameters.
70 | - parameter writeKey: Write Key for your Segment project
71 | - parameter queue: In memory queue of enqueued events.
72 | - parameter executor: Executor that handles interactions with the messageQueue. This will also be used to upload events.
73 | Exposed for testing only. Do not use this directly.
74 | */
75 |
76 | public init(writeKey: String, queue: [[String: AnyObject]], executor: Executor) {
77 | self.writeKey = writeKey
78 | self.messageQueue = queue
79 | self.executor = executor
80 | }
81 |
82 | /**
83 | Enqueue the given message to be uploaded to Segment asynchronously.
84 | This function will call MessageBuilder.build and validate the message.
85 | - parameter messageBuilder: The builder instance used to a create a message. Be sure to provide a userId or anonymousId.
86 | */
87 |
88 | public func enqueue(messageBuilder: MessageBuilder) {
89 | var message = messageBuilder.build()
90 | Analytics.ensureId(message: message)
91 | message["messageId"] = UUID().uuidString as AnyObject
92 | message["timestamp"] = now as AnyObject
93 | executor.submit {
94 | self.messageQueue.append(message)
95 | if self.messageQueue.count >= self.flushQueueSize {
96 | self.performFlush()
97 | }
98 | }
99 | }
100 |
101 | /**
102 | Request the client to upload events. This method will asychronously upload the events, and will not block.
103 | */
104 |
105 | public func flush() {
106 | executor.submit(task: performFlush)
107 | }
108 |
109 | // MARK: Private methods
110 |
111 | /**
112 | Ensures that a message provides either one of userId or anonymousId.
113 | */
114 |
115 | private static func ensureId(message: [String: AnyObject]) {
116 | let idExists = message.keys.contains("userId") || message.keys.contains("anonymousId")
117 | assert(idExists, "Either userId or anonymousId must be provided.")
118 | }
119 |
120 | /**
121 | Returns a URLRequest for the given endpoint (relative to https://api.segment.io/v1 by default).
122 | */
123 |
124 | private func request(endpoint: String) -> URLRequest {
125 | return URLRequest(url: URL(string: "https://api.segment.io/v1" + endpoint)!)
126 | }
127 |
128 | /**
129 | Returns the current time as an ISO 8601 formatted String.
130 | */
131 |
132 | private var now: String {
133 | let formatter = DateFormatter()
134 | formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z"
135 | formatter.timeZone = TimeZone(secondsFromGMT: 0)
136 | formatter.calendar = Calendar(identifier: .iso8601)
137 | formatter.locale = Locale(identifier: "en_US_POSIX")
138 | return formatter.string(from: Date())
139 | }
140 |
141 | /**
142 | Synchronously flush events to Segment.
143 | */
144 |
145 | private func performFlush() {
146 | guard messageQueue.count > 0 else {
147 | print("No messages to flush")
148 | return
149 | }
150 | guard let messagesData = messagesData else {
151 | print("Failed to serialize messages. Dropping \(messageQueue.count) messages.")
152 | messageQueue.removeAll(keepingCapacity: true)
153 | return
154 | }
155 | let request = urlRequest(for: messagesData)
156 | print("Uploading \(messageQueue.count) messages.")
157 | let dataTask = URLSession.shared.dataTask(with: request)
158 | dataTask.resume()
159 | messageQueue.removeAll(keepingCapacity: true)
160 | }
161 |
162 | /**
163 | Returns serialized events.
164 | */
165 |
166 | private var messagesData: Data? {
167 | let batch: [String: AnyObject] = [
168 | "batch": messageQueue as AnyObject,
169 | "context": [
170 | "library": [
171 | "name": "analytics-swift",
172 | "version": AnalyticsSwiftVersionNumber
173 | ]
174 | ] as AnyObject
175 | ]
176 | return try? JSONSerialization.data(withJSONObject: batch, options: [])
177 | }
178 |
179 | /**
180 | Returns URLRequest to be fired to send events to Segment.
181 | */
182 |
183 | private func urlRequest(for messagesData: Data) -> URLRequest {
184 | var urlRequest = request(endpoint: "/import")
185 | urlRequest.httpMethod = "post"
186 | urlRequest.setValue("gzip", forHTTPHeaderField: "Accept-Encoding")
187 | urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
188 | urlRequest.setValue(Credentials.basic(username: writeKey, password: ""), forHTTPHeaderField: "Authorization")
189 | urlRequest.httpBody = messagesData
190 | return urlRequest
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/AnalyticsSwift/AnalyticsSwift.h:
--------------------------------------------------------------------------------
1 | //
2 | // AnalyticsSwift.h
3 | // AnalyticsSwift
4 | //
5 | // Created by Prateek Srivastava on 2015-06-10.
6 | // Copyright (c) 2015 Segment. All rights reserved.
7 | //
8 |
9 | #include
10 |
11 | #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE || TARGET_OS_TVOS
12 |
13 | #import
14 |
15 |
16 | #else
17 |
18 | #import
19 |
20 |
21 | #endif
22 |
23 |
24 | //! Project version number for AnalyticsSwift.
25 | FOUNDATION_EXPORT double AnalyticsSwiftVersionNumber;
26 |
27 | //! Project version string for AnalyticsSwift.
28 | FOUNDATION_EXPORT const unsigned char AnalyticsSwiftVersionString[];
29 |
30 | // In this header, you should import all the public headers of your framework using statements like #import
31 |
32 |
33 |
--------------------------------------------------------------------------------
/AnalyticsSwift/Credentials.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright © 2015 Segment, Inc.
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Foundation
24 |
25 | /**
26 | Factory for HTTP authorization credentials. Exposed for testing.
27 | */
28 |
29 | public class Credentials {
30 |
31 | /**
32 | Returns an auth credential for the Basic scheme. Exposed for testing.
33 | */
34 |
35 | public static func basic(username: String, password: String) -> String {
36 | return String(format: "Basic %@", String(format: "%@:%@", username, password).base64)
37 | }
38 | }
39 |
40 | extension String {
41 |
42 | /**
43 | Returns Base64 encoded string.
44 | */
45 |
46 | var base64: String {
47 | let utf8str = data(using: .utf8, allowLossyConversion: false)
48 | return utf8str?.base64EncodedString(options: .lineLength64Characters) ?? ""
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/AnalyticsSwift/Executor.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright © 2015 Segment, Inc.
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Foundation
24 |
25 | /**
26 | Abstraction for enqueing tasks. This interface provides a way of decoupling task submission
27 | from the mechanics of how each task will be run, including details of thread use, scheduling, etc.
28 | Exposed for testing.
29 | */
30 |
31 | public protocol Executor {
32 | func submit(task: @escaping () -> ())
33 | }
34 |
--------------------------------------------------------------------------------
/AnalyticsSwift/GroupMessageBuilder.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright © 2015 Segment, Inc.
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Foundation
24 |
25 | public class GroupMessageBuilder: MessageBuilder {
26 | private var dictionary: [String: AnyObject] = [:]
27 |
28 | public init(groupId: String) {
29 | dictionary["type"] = "group" as AnyObject
30 | dictionary["groupId"] = groupId as AnyObject
31 | }
32 |
33 | public func traits(_ traits: [String: AnyObject]) -> GroupMessageBuilder {
34 | dictionary["traits"] = traits as AnyObject
35 | return self
36 | }
37 |
38 | // Common
39 |
40 | public func userId(_ userId: String) -> GroupMessageBuilder {
41 | dictionary["userId"] = userId as AnyObject
42 | return self
43 | }
44 |
45 | public func anonymousId(_ anonymousId: String) -> GroupMessageBuilder {
46 | dictionary["anonymousId"] = anonymousId as AnyObject
47 | return self
48 | }
49 |
50 | public func context(_ context: [String: AnyObject]) -> GroupMessageBuilder {
51 | dictionary["context"] = context as AnyObject
52 | return self
53 | }
54 |
55 | public func build() -> [String: AnyObject] {
56 | return dictionary
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/AnalyticsSwift/IdentifyMessageBuilder.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright © 2015 Segment, Inc.
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Foundation
24 |
25 | public class IdentifyMessageBuilder: MessageBuilder {
26 | private var dictionary: [String: AnyObject] = [:]
27 |
28 | public init() {
29 | dictionary["type"] = "identify" as AnyObject
30 | }
31 |
32 | public func traits(_ traits: [String: AnyObject]) -> IdentifyMessageBuilder {
33 | dictionary["traits"] = traits as AnyObject
34 | return self
35 | }
36 |
37 | // Common
38 |
39 | public func userId(_ userId: String) -> IdentifyMessageBuilder {
40 | dictionary["userId"] = userId as AnyObject
41 | return self
42 | }
43 |
44 | public func anonymousId(_ anonymousId: String) -> IdentifyMessageBuilder {
45 | dictionary["anonymousId"] = anonymousId as AnyObject
46 | return self
47 | }
48 |
49 | public func context(_ context: [String: AnyObject]) -> IdentifyMessageBuilder {
50 | dictionary["context"] = context as AnyObject
51 | return self
52 | }
53 |
54 | public func build() -> [String: AnyObject] {
55 | return dictionary
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/AnalyticsSwift/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2015 Segment. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/AnalyticsSwift/MessageBuilder.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright © 2015 Segment, Inc.
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Foundation
24 |
25 | public protocol MessageBuilder {
26 | func build() -> [String: AnyObject]
27 | }
28 |
--------------------------------------------------------------------------------
/AnalyticsSwift/ScreenMessageBuilder.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright © 2015 Segment, Inc.
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Foundation
24 |
25 | public class ScreenMessageBuilder: MessageBuilder {
26 | private var dictionary: [String: AnyObject] = [:]
27 |
28 | public init(name: String) {
29 | dictionary["type"] = "screen" as AnyObject
30 | dictionary["name"] = name as AnyObject
31 | }
32 |
33 | public func properties(_ properties: [String: AnyObject]) -> ScreenMessageBuilder {
34 | dictionary["properties"] = properties as AnyObject
35 | return self
36 | }
37 |
38 | // Common
39 |
40 | public func userId(_ userId: String) -> ScreenMessageBuilder {
41 | dictionary["userId"] = userId as AnyObject
42 | return self
43 | }
44 |
45 | public func anonymousId(_ anonymousId: String) -> ScreenMessageBuilder {
46 | dictionary["anonymousId"] = anonymousId as AnyObject
47 | return self
48 | }
49 |
50 | public func context(_ context: [String: AnyObject]) -> ScreenMessageBuilder {
51 | dictionary["context"] = context as AnyObject
52 | return self
53 | }
54 |
55 | public func build() -> [String: AnyObject] {
56 | return dictionary
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/AnalyticsSwift/SerialExecutor.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright © 2015 Segment, Inc.
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Foundation
24 |
25 | /**
26 | An Executor implementation that runs all enqueued tasks serially and asynchronously.
27 | */
28 |
29 | public class SerialExecutor: Executor {
30 | private let dispatcher: DispatchQueue
31 |
32 | init(name: String) {
33 | self.dispatcher = DispatchQueue(label: name)
34 | }
35 |
36 | public func submit(task: @escaping () -> ()) {
37 | dispatcher.async(execute: task)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/AnalyticsSwift/TrackMessageBuilder.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright © 2015 Segment, Inc.
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Foundation
24 |
25 | public class TrackMessageBuilder: MessageBuilder {
26 | private var dictionary: [String: AnyObject] = [:]
27 |
28 | public init(event: String) {
29 | dictionary["type"] = "track" as AnyObject
30 | dictionary["event"] = event as AnyObject
31 | }
32 |
33 | public func properties(properties: [String: AnyObject]) -> TrackMessageBuilder {
34 | dictionary["properties"] = properties as AnyObject
35 | return self
36 | }
37 |
38 | // Common
39 |
40 | public func userId(_ userId: String) -> TrackMessageBuilder {
41 | dictionary["userId"] = userId as AnyObject
42 | return self
43 | }
44 |
45 | public func anonymousId(_ anonymousId: String) -> TrackMessageBuilder {
46 | dictionary["anonymousId"] = anonymousId as AnyObject
47 | return self
48 | }
49 |
50 | public func context(_ context: [String: AnyObject]) -> TrackMessageBuilder {
51 | dictionary["context"] = context as AnyObject
52 | return self
53 | }
54 |
55 | public func build() -> [String: AnyObject] {
56 | return dictionary
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample.xcodeproj/xcshareddata/xcschemes/AnalyticsSwiftExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // AnalyticsSwiftExample
4 | //
5 | // Created by William Grosset on 2/12/19.
6 | // Copyright © 2019 Segment. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Analytics
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | var window: UIWindow?
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | let config = SEGAnalyticsConfiguration(writeKey: "YOUR_WRITE_KEY")
19 | config.trackApplicationLifecycleEvents = true
20 | SEGAnalytics.setup(with: config)
21 | return true
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/base_small.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "base_small.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/base_small.imageset/base_small.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/segment-boneyard/analytics-swift/f96417b55e3ba99891d59ef60671feb9ca9ae6df/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/base_small.imageset/base_small.jpg
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/segment_logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "segment_logo.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/segment_logo.imageset/segment_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/segment-boneyard/analytics-swift/f96417b55e3ba99891d59ef60671feb9ca9ae6df/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/segment_logo.imageset/segment_logo.png
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/stack_small.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "stack_small.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/stack_small.imageset/stack_small.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/segment-boneyard/analytics-swift/f96417b55e3ba99891d59ef60671feb9ca9ae6df/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/stack_small.imageset/stack_small.jpg
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/stack_smaller.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "stack_smaller.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/stack_smaller.imageset/stack_smaller.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/segment-boneyard/analytics-swift/f96417b55e3ba99891d59ef60671feb9ca9ae6df/AnalyticsSwiftExample/AnalyticsSwiftExample/Assets.xcassets/stack_smaller.imageset/stack_smaller.jpg
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
38 |
39 |
40 |
41 |
42 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
76 |
77 |
78 |
79 |
80 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/PageViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PageViewController.swift
3 | // AnalyticsSwiftExample
4 | //
5 | // Created by William Grosset on 2/13/19.
6 | // Copyright © 2019 Segment. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class PageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {
12 |
13 | lazy var orderedViewControllers: [UIViewController] = {
14 | return [self.newViewController(viewController: "sbPrimary"),
15 | self.newViewController(viewController: "sbSecondary")]
16 | }()
17 |
18 | var pageControl = UIPageControl()
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 |
23 | self.delegate = self
24 | self.dataSource = self
25 |
26 | if let firstViewController = orderedViewControllers.first {
27 | setViewControllers([firstViewController],
28 | direction: .forward,
29 | animated: true,
30 | completion: nil)
31 | }
32 | configurePageControl()
33 | }
34 |
35 | func configurePageControl() {
36 | pageControl = UIPageControl(frame: CGRect(x: 0, y: UIScreen.main.bounds.maxY - 50, width: UIScreen.main.bounds.width, height: 50))
37 | pageControl.numberOfPages = orderedViewControllers.count
38 | pageControl.currentPage = 0
39 | pageControl.tintColor = UIColor.black
40 | pageControl.pageIndicatorTintColor = UIColor.black
41 | pageControl.currentPageIndicatorTintColor = UIColor(red: 73/255, green: 184/255, blue: 130/255, alpha: 1)
42 | self.view.addSubview(pageControl)
43 | }
44 |
45 | func newViewController(viewController: String) -> UIViewController {
46 | return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: viewController)
47 | }
48 |
49 | func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
50 | guard let viewControllerIndex = orderedViewControllers.index(of: viewController) else {
51 | return nil
52 | }
53 |
54 | let previousIndex = viewControllerIndex - 1
55 |
56 | guard previousIndex >= 0 else {
57 | return nil
58 | }
59 |
60 | guard orderedViewControllers.count > previousIndex else {
61 | return nil
62 | }
63 |
64 | return orderedViewControllers[previousIndex]
65 | }
66 |
67 | func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
68 | guard let viewControllerIndex = orderedViewControllers.index(of: viewController) else {
69 | return nil
70 | }
71 |
72 | let nextIndex = viewControllerIndex + 1
73 |
74 | guard orderedViewControllers.count != nextIndex else {
75 | return nil
76 | }
77 |
78 | guard orderedViewControllers.count > nextIndex else {
79 | return nil
80 | }
81 |
82 | return orderedViewControllers[nextIndex]
83 | }
84 |
85 | func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
86 | let pageContentViewController = pageViewController.viewControllers![0]
87 | self.pageControl.currentPage = orderedViewControllers.index(of: pageContentViewController)!
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/PrimaryViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PrimaryViewController.swift
3 | // AnalyticsSwiftExample
4 | //
5 | // Created by William Grosset on 2/12/19.
6 | // Copyright © 2019 Segment. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Analytics
11 |
12 | class PrimaryViewController: UIViewController {
13 |
14 | override func viewDidAppear(_ animated: Bool) {
15 | super.viewDidAppear(animated)
16 | SEGAnalytics.shared().screen("Home")
17 | SEGAnalytics.shared().flush()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/AnalyticsSwiftExample/SecondaryViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SecondaryViewController.swift
3 | // AnalyticsSwiftExample
4 | //
5 | // Created by William Grosset on 2/12/19.
6 | // Copyright © 2019 Segment. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Analytics
11 |
12 | class SecondaryViewController: UIViewController {
13 |
14 | @IBOutlet weak var button: UIButton!
15 |
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 | button.layer.cornerRadius = 10
19 | button.layer.shadowColor = UIColor.black.cgColor
20 | button.layer.shadowOffset = CGSize(width: 0, height: 5)
21 | button.layer.shadowRadius = 5
22 | button.layer.shadowOpacity = 0.4
23 | button.titleLabel?.textAlignment = NSTextAlignment.center
24 | }
25 |
26 | override func viewDidAppear(_ animated: Bool) {
27 | super.viewDidAppear(animated)
28 | SEGAnalytics.shared().screen("About")
29 | SEGAnalytics.shared().flush()
30 | }
31 |
32 | @IBAction func buttonClicked(_ sender: Any) {
33 | SEGAnalytics.shared().track("Learn About Segment Clicked")
34 | guard let url = URL(string: "https://github.com/segmentio/analytics-ios/blob/master/README.md#quickstart") else { return }
35 | UIApplication.shared.open(url)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '11.0'
2 |
3 | target 'AnalyticsSwiftExample' do
4 | use_frameworks!
5 |
6 | pod 'Analytics', '3.6.10'
7 | end
8 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Analytics (3.6.10)
3 |
4 | DEPENDENCIES:
5 | - Analytics (= 3.6.10)
6 |
7 | SPEC REPOS:
8 | https://github.com/cocoapods/specs.git:
9 | - Analytics
10 |
11 | SPEC CHECKSUMS:
12 | Analytics: 63744ad4afa65c3bcdcdb7a94b62515bde5b3900
13 |
14 | PODFILE CHECKSUM: 1078e7b12a3b5e456d114d57af4de4aca03fb029
15 |
16 | COCOAPODS: 1.6.0
17 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Crypto/SEGAES256Crypto.h:
--------------------------------------------------------------------------------
1 | //
2 | // SEGAES256Crypto.h
3 | // Analytics
4 | //
5 | // Copyright © 2016 Segment. All rights reserved.
6 | //
7 |
8 | #import
9 | #import "SEGCrypto.h"
10 |
11 |
12 | @interface SEGAES256Crypto : NSObject
13 |
14 | @property (nonatomic, readonly, nonnull) NSString *password;
15 | @property (nonatomic, readonly, nonnull) NSData *salt;
16 | @property (nonatomic, readonly, nonnull) NSData *iv;
17 |
18 | - (instancetype _Nonnull)initWithPassword:(NSString *_Nonnull)password salt:(NSData *_Nonnull)salt iv:(NSData *_Nonnull)iv;
19 | // Convenient shorthand. Will randomly generate salt and iv.
20 | - (instancetype _Nonnull)initWithPassword:(NSString *_Nonnull)password;
21 |
22 | + (NSData *_Nonnull)randomDataOfLength:(size_t)length;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Crypto/SEGAES256Crypto.m:
--------------------------------------------------------------------------------
1 | //
2 | // SEGAES256Crypto.m
3 | // Analytics
4 | //
5 | // Copyright © 2016 Segment. All rights reserved.
6 | //
7 |
8 |
9 | #import
10 | #import
11 | #import "SEGAES256Crypto.h"
12 | #import "SEGUtils.h"
13 |
14 | // Implementation courtesy of http://robnapier.net/aes-commoncrypto
15 |
16 | static NSString *const kRNCryptManagerErrorDomain = @"com.segment.crypto";
17 |
18 | static const CCAlgorithm kAlgorithm = kCCAlgorithmAES;
19 | static const NSUInteger kAlgorithmKeySize = kCCKeySizeAES256;
20 | static const NSUInteger kAlgorithmBlockSize = kCCBlockSizeAES128;
21 | static const NSUInteger kAlgorithmIVSize = kCCBlockSizeAES128;
22 | static const NSUInteger kPBKDFSaltSize = 8;
23 | static const NSUInteger kPBKDFRounds = 10000; // ~80ms on an iPhone 4
24 |
25 |
26 | @implementation SEGAES256Crypto
27 |
28 | - (instancetype)initWithPassword:(NSString *)password salt:(NSData *)salt iv:(NSData *_Nonnull)iv
29 | {
30 | if (self = [super init]) {
31 | _password = password;
32 | _salt = salt;
33 | _iv = iv;
34 | }
35 | return self;
36 | }
37 |
38 | - (instancetype)initWithPassword:(NSString *)password
39 | {
40 | NSData *iv = [SEGAES256Crypto randomDataOfLength:kAlgorithmIVSize];
41 | NSData *salt = [SEGAES256Crypto randomDataOfLength:kPBKDFSaltSize];
42 | return [self initWithPassword:password salt:salt iv:iv];
43 | }
44 |
45 | - (NSData *)aesKey
46 | {
47 | return [[self class] AESKeyForPassword:self.password salt:self.salt];
48 | }
49 |
50 | - (NSData *)encrypt:(NSData *)data
51 | {
52 | size_t outLength;
53 | NSMutableData *cipherData = [NSMutableData dataWithLength:data.length + kAlgorithmBlockSize];
54 |
55 | CCCryptorStatus
56 | result = CCCrypt(kCCEncrypt, // operation
57 | kAlgorithm, // Algorithm
58 | kCCOptionPKCS7Padding, // options
59 | self.aesKey.bytes, // key
60 | self.aesKey.length, // keylength
61 | self.iv.bytes, // iv
62 | data.bytes, // dataIn
63 | data.length, // dataInLength,
64 | cipherData.mutableBytes, // dataOut
65 | cipherData.length, // dataOutAvailable
66 | &outLength); // dataOutMoved
67 |
68 | if (result == kCCSuccess) {
69 | cipherData.length = outLength;
70 | } else {
71 | NSError *error = [NSError errorWithDomain:kRNCryptManagerErrorDomain
72 | code:result
73 | userInfo:nil];
74 | SEGLog(@"Unable to encrypt data", error);
75 | return nil;
76 | }
77 | return cipherData;
78 | }
79 |
80 | - (NSData *)decrypt:(NSData *)data
81 | {
82 | size_t outLength;
83 | NSMutableData *decryptedData = [NSMutableData dataWithLength:data.length + kAlgorithmBlockSize];
84 |
85 | CCCryptorStatus
86 | result = CCCrypt(kCCDecrypt, // operation
87 | kAlgorithm, // Algorithm
88 | kCCOptionPKCS7Padding, // options
89 | self.aesKey.bytes, // key
90 | self.aesKey.length, // keylength
91 | self.iv.bytes, // iv
92 | data.bytes, // dataIn
93 | data.length, // dataInLength,
94 | decryptedData.mutableBytes, // dataOut
95 | decryptedData.length, // dataOutAvailable
96 | &outLength); // dataOutMoved
97 |
98 | if (result == kCCSuccess) {
99 | decryptedData.length = outLength;
100 | } else {
101 | NSError *error = [NSError errorWithDomain:kRNCryptManagerErrorDomain
102 | code:result
103 | userInfo:nil];
104 | SEGLog(@"Unable to decrypt data", error);
105 | return nil;
106 | }
107 | return decryptedData;
108 | }
109 |
110 | + (NSData *)randomDataOfLength:(size_t)length
111 | {
112 | NSMutableData *data = [NSMutableData dataWithLength:length];
113 |
114 | int result = SecRandomCopyBytes(kSecRandomDefault,
115 | length,
116 | data.mutableBytes);
117 | if (result != kCCSuccess) {
118 | SEGLog(@"Unable to generate random bytes: %d", result);
119 | }
120 |
121 | return data;
122 | }
123 |
124 | // Replace this with a 10,000 hash calls if you don't have CCKeyDerivationPBKDF
125 | + (NSData *)AESKeyForPassword:(NSString *)password
126 | salt:(NSData *)salt
127 | {
128 | NSMutableData *derivedKey = [NSMutableData dataWithLength:kAlgorithmKeySize];
129 |
130 | int result = CCKeyDerivationPBKDF(kCCPBKDF2, // algorithm
131 | password.UTF8String, // password
132 | [password lengthOfBytesUsingEncoding:NSUTF8StringEncoding], // passwordLength
133 | salt.bytes, // salt
134 | salt.length, // saltLen
135 | kCCPRFHmacAlgSHA1, // PRF
136 | kPBKDFRounds, // rounds
137 | derivedKey.mutableBytes, // derivedKey
138 | derivedKey.length); // derivedKeyLen
139 |
140 | // Do not log password here
141 | if (result != kCCSuccess) {
142 | SEGLog(@"Unable to create AES key for password: %d", result);
143 | }
144 |
145 | return derivedKey;
146 | }
147 |
148 | @end
149 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Crypto/SEGCrypto.h:
--------------------------------------------------------------------------------
1 | //
2 | // SEGCrypto.h
3 | // Analytics
4 | //
5 | // Copyright © 2016 Segment. All rights reserved.
6 | //
7 |
8 | #import
9 |
10 | @protocol SEGCrypto
11 |
12 | - (NSData *_Nullable)encrypt:(NSData *_Nonnull)data;
13 | - (NSData *_Nullable)decrypt:(NSData *_Nonnull)data;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGAliasPayload.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "SEGPayload.h"
3 |
4 | NS_ASSUME_NONNULL_BEGIN
5 |
6 |
7 | @interface SEGAliasPayload : SEGPayload
8 |
9 | @property (nonatomic, readonly) NSString *theNewId;
10 |
11 | - (instancetype)initWithNewId:(NSString *)newId
12 | context:(JSON_DICT)context
13 | integrations:(JSON_DICT)integrations;
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGAliasPayload.m:
--------------------------------------------------------------------------------
1 | #import "SEGAliasPayload.h"
2 |
3 |
4 | @implementation SEGAliasPayload
5 |
6 | - (instancetype)initWithNewId:(NSString *)newId
7 | context:(NSDictionary *)context
8 | integrations:(NSDictionary *)integrations
9 | {
10 | if (self = [super initWithContext:context integrations:integrations]) {
11 | _theNewId = [newId copy];
12 | }
13 | return self;
14 | }
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGGroupPayload.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "SEGPayload.h"
3 |
4 | NS_ASSUME_NONNULL_BEGIN
5 |
6 |
7 | @interface SEGGroupPayload : SEGPayload
8 |
9 | @property (nonatomic, readonly) NSString *groupId;
10 |
11 | @property (nonatomic, readonly, nullable) JSON_DICT traits;
12 |
13 | - (instancetype)initWithGroupId:(NSString *)groupId
14 | traits:(JSON_DICT _Nullable)traits
15 | context:(JSON_DICT)context
16 | integrations:(JSON_DICT)integrations;
17 |
18 | @end
19 |
20 | NS_ASSUME_NONNULL_END
21 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGGroupPayload.m:
--------------------------------------------------------------------------------
1 | #import "SEGGroupPayload.h"
2 |
3 |
4 | @implementation SEGGroupPayload
5 |
6 | - (instancetype)initWithGroupId:(NSString *)groupId
7 | traits:(NSDictionary *)traits
8 | context:(NSDictionary *)context
9 | integrations:(NSDictionary *)integrations
10 | {
11 | if (self = [super initWithContext:context integrations:integrations]) {
12 | _groupId = [groupId copy];
13 | _traits = [traits copy];
14 | }
15 | return self;
16 | }
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGIdentifyPayload.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "SEGPayload.h"
3 |
4 | NS_ASSUME_NONNULL_BEGIN
5 |
6 |
7 | @interface SEGIdentifyPayload : SEGPayload
8 |
9 | @property (nonatomic, readonly, nullable) NSString *userId;
10 |
11 | @property (nonatomic, readonly, nullable) NSString *anonymousId;
12 |
13 | @property (nonatomic, readonly, nullable) JSON_DICT traits;
14 |
15 | - (instancetype)initWithUserId:(NSString *)userId
16 | anonymousId:(NSString *_Nullable)anonymousId
17 | traits:(JSON_DICT _Nullable)traits
18 | context:(JSON_DICT)context
19 | integrations:(JSON_DICT)integrations;
20 |
21 | @end
22 |
23 | NS_ASSUME_NONNULL_END
24 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGIdentifyPayload.m:
--------------------------------------------------------------------------------
1 | #import "SEGIdentifyPayload.h"
2 |
3 |
4 | @implementation SEGIdentifyPayload
5 |
6 | - (instancetype)initWithUserId:(NSString *)userId
7 | anonymousId:(NSString *)anonymousId
8 | traits:(NSDictionary *)traits
9 | context:(NSDictionary *)context
10 | integrations:(NSDictionary *)integrations
11 | {
12 | if (self = [super initWithContext:context integrations:integrations]) {
13 | _userId = [userId copy];
14 | _anonymousId = [anonymousId copy];
15 | _traits = [traits copy];
16 | }
17 | return self;
18 | }
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGIntegration.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "SEGIdentifyPayload.h"
3 | #import "SEGTrackPayload.h"
4 | #import "SEGScreenPayload.h"
5 | #import "SEGAliasPayload.h"
6 | #import "SEGIdentifyPayload.h"
7 | #import "SEGGroupPayload.h"
8 | #import "SEGContext.h"
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @protocol SEGIntegration
13 |
14 | @optional
15 | // Identify will be called when the user calls either of the following:
16 | // 1. [[SEGAnalytics sharedInstance] identify:someUserId];
17 | // 2. [[SEGAnalytics sharedInstance] identify:someUserId traits:someTraits];
18 | // 3. [[SEGAnalytics sharedInstance] identify:someUserId traits:someTraits options:someOptions];
19 | // @see https://segment.com/docs/spec/identify/
20 | - (void)identify:(SEGIdentifyPayload *)payload;
21 |
22 | // Track will be called when the user calls either of the following:
23 | // 1. [[SEGAnalytics sharedInstance] track:someEvent];
24 | // 2. [[SEGAnalytics sharedInstance] track:someEvent properties:someProperties];
25 | // 3. [[SEGAnalytics sharedInstance] track:someEvent properties:someProperties options:someOptions];
26 | // @see https://segment.com/docs/spec/track/
27 | - (void)track:(SEGTrackPayload *)payload;
28 |
29 | // Screen will be called when the user calls either of the following:
30 | // 1. [[SEGAnalytics sharedInstance] screen:someEvent];
31 | // 2. [[SEGAnalytics sharedInstance] screen:someEvent properties:someProperties];
32 | // 3. [[SEGAnalytics sharedInstance] screen:someEvent properties:someProperties options:someOptions];
33 | // @see https://segment.com/docs/spec/screen/
34 | - (void)screen:(SEGScreenPayload *)payload;
35 |
36 | // Group will be called when the user calls either of the following:
37 | // 1. [[SEGAnalytics sharedInstance] group:someGroupId];
38 | // 2. [[SEGAnalytics sharedInstance] group:someGroupId traits:];
39 | // 3. [[SEGAnalytics sharedInstance] group:someGroupId traits:someGroupTraits options:someOptions];
40 | // @see https://segment.com/docs/spec/group/
41 | - (void)group:(SEGGroupPayload *)payload;
42 |
43 | // Alias will be called when the user calls either of the following:
44 | // 1. [[SEGAnalytics sharedInstance] alias:someNewId];
45 | // 2. [[SEGAnalytics sharedInstance] alias:someNewId options:someOptions];
46 | // @see https://segment.com/docs/spec/alias/
47 | - (void)alias:(SEGAliasPayload *)payload;
48 |
49 | // Reset is invoked when the user logs out, and any data saved about the user should be cleared.
50 | - (void)reset;
51 |
52 | // Flush is invoked when any queued events should be uploaded.
53 | - (void)flush;
54 |
55 | // App Delegate Callbacks
56 |
57 | // Callbacks for notifications changes.
58 | // ------------------------------------
59 | - (void)receivedRemoteNotification:(NSDictionary *)userInfo;
60 | - (void)failedToRegisterForRemoteNotificationsWithError:(NSError *)error;
61 | - (void)registeredForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
62 | - (void)handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo;
63 |
64 | // Callbacks for app state changes
65 | // -------------------------------
66 |
67 | - (void)applicationDidFinishLaunching:(NSNotification *)notification;
68 | - (void)applicationDidEnterBackground;
69 | - (void)applicationWillEnterForeground;
70 | - (void)applicationWillTerminate;
71 | - (void)applicationWillResignActive;
72 | - (void)applicationDidBecomeActive;
73 |
74 | - (void)continueUserActivity:(NSUserActivity *)activity;
75 | - (void)openURL:(NSURL *)url options:(NSDictionary *)options;
76 |
77 | @end
78 |
79 | NS_ASSUME_NONNULL_END
80 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGIntegrationFactory.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "SEGIntegration.h"
3 | #import "SEGAnalytics.h"
4 |
5 | NS_ASSUME_NONNULL_BEGIN
6 |
7 | @class SEGAnalytics;
8 |
9 | @protocol SEGIntegrationFactory
10 |
11 | /**
12 | * Attempts to create an adapter with the given settings. Returns the adapter if one was created, or null
13 | * if this factory isn't capable of creating such an adapter.
14 | */
15 | - (id)createWithSettings:(NSDictionary *)settings forAnalytics:(SEGAnalytics *)analytics;
16 |
17 | /** The key for which this factory can create an Integration. */
18 | - (NSString *)key;
19 |
20 | @end
21 |
22 | NS_ASSUME_NONNULL_END
23 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGIntegrationsManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // SEGIntegrationsManager.h
3 | // Analytics
4 | //
5 | // Created by Tony Xiao on 9/20/16.
6 | // Copyright © 2016 Segment. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "SEGMiddleware.h"
11 |
12 | /**
13 | * NSNotification name, that is posted after integrations are loaded.
14 | */
15 | extern NSString *_Nonnull SEGAnalyticsIntegrationDidStart;
16 |
17 | @class SEGAnalytics;
18 |
19 |
20 | @interface SEGIntegrationsManager : NSObject
21 |
22 | // Exposed for testing.
23 | + (BOOL)isTrackEvent:(NSString *_Nonnull)event enabledForIntegration:(NSString *_Nonnull)key inPlan:(NSDictionary *_Nonnull)plan;
24 |
25 | // @Deprecated - Exposing for backward API compat reasons only
26 | @property (nonatomic, readonly) NSMutableDictionary *_Nonnull registeredIntegrations;
27 |
28 | - (instancetype _Nonnull)initWithAnalytics:(SEGAnalytics *_Nonnull)analytics;
29 |
30 | // @Deprecated - Exposing for backward API compat reasons only
31 | - (NSString *_Nonnull)getAnonymousId;
32 |
33 | @end
34 |
35 |
36 | @interface SEGIntegrationsManager (SEGMiddleware)
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGPayload.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "SEGSerializableValue.h"
3 |
4 | NS_ASSUME_NONNULL_BEGIN
5 |
6 |
7 | @interface SEGPayload : NSObject
8 |
9 | @property (nonatomic, readonly) JSON_DICT context;
10 | @property (nonatomic, readonly) JSON_DICT integrations;
11 |
12 | - (instancetype)initWithContext:(JSON_DICT)context integrations:(JSON_DICT)integrations;
13 |
14 | @end
15 |
16 |
17 | @interface SEGApplicationLifecyclePayload : SEGPayload
18 |
19 | @property (nonatomic, strong) NSString *notificationName;
20 |
21 | // ApplicationDidFinishLaunching only
22 | @property (nonatomic, strong, nullable) NSDictionary *launchOptions;
23 |
24 | @end
25 |
26 |
27 | @interface SEGContinueUserActivityPayload : SEGPayload
28 |
29 | @property (nonatomic, strong) NSUserActivity *activity;
30 |
31 | @end
32 |
33 |
34 | @interface SEGOpenURLPayload : SEGPayload
35 |
36 | @property (nonatomic, strong) NSURL *url;
37 | @property (nonatomic, strong) NSDictionary *options;
38 |
39 | @end
40 |
41 | NS_ASSUME_NONNULL_END
42 |
43 |
44 | @interface SEGRemoteNotificationPayload : SEGPayload
45 |
46 | // SEGEventTypeHandleActionWithForRemoteNotification
47 | @property (nonatomic, strong, nullable) NSString *actionIdentifier;
48 |
49 | // SEGEventTypeHandleActionWithForRemoteNotification
50 | // SEGEventTypeReceivedRemoteNotification
51 | @property (nonatomic, strong, nullable) NSDictionary *userInfo;
52 |
53 | // SEGEventTypeFailedToRegisterForRemoteNotifications
54 | @property (nonatomic, strong, nullable) NSError *error;
55 |
56 | // SEGEventTypeRegisteredForRemoteNotifications
57 | @property (nonatomic, strong, nullable) NSData *deviceToken;
58 |
59 | @end
60 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGPayload.m:
--------------------------------------------------------------------------------
1 | #import "SEGPayload.h"
2 |
3 |
4 | @implementation SEGPayload
5 |
6 | - (instancetype)initWithContext:(NSDictionary *)context integrations:(NSDictionary *)integrations
7 | {
8 | if (self = [super init]) {
9 | _context = [context copy];
10 | _integrations = [integrations copy];
11 | }
12 | return self;
13 | }
14 |
15 | @end
16 |
17 |
18 | @implementation SEGApplicationLifecyclePayload
19 |
20 | @end
21 |
22 |
23 | @implementation SEGRemoteNotificationPayload
24 |
25 | @end
26 |
27 |
28 | @implementation SEGContinueUserActivityPayload
29 |
30 | @end
31 |
32 |
33 | @implementation SEGOpenURLPayload
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGScreenPayload.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "SEGPayload.h"
3 |
4 | NS_ASSUME_NONNULL_BEGIN
5 |
6 |
7 | @interface SEGScreenPayload : SEGPayload
8 |
9 | @property (nonatomic, readonly) NSString *name;
10 |
11 | @property (nonatomic, readonly, nullable) NSString *category;
12 |
13 | @property (nonatomic, readonly, nullable) NSDictionary *properties;
14 |
15 | - (instancetype)initWithName:(NSString *)name
16 | properties:(NSDictionary *_Nullable)properties
17 | context:(NSDictionary *)context
18 | integrations:(NSDictionary *)integrations;
19 |
20 | @end
21 |
22 | NS_ASSUME_NONNULL_END
23 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGScreenPayload.m:
--------------------------------------------------------------------------------
1 | #import "SEGScreenPayload.h"
2 |
3 |
4 | @implementation SEGScreenPayload
5 |
6 | - (instancetype)initWithName:(NSString *)name
7 | properties:(NSDictionary *)properties
8 | context:(NSDictionary *)context
9 | integrations:(NSDictionary *)integrations
10 | {
11 | if (self = [super initWithContext:context integrations:integrations]) {
12 | _name = [name copy];
13 | _properties = [properties copy];
14 | }
15 | return self;
16 | }
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGTrackPayload.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "SEGPayload.h"
3 |
4 | NS_ASSUME_NONNULL_BEGIN
5 |
6 |
7 | @interface SEGTrackPayload : SEGPayload
8 |
9 | @property (nonatomic, readonly) NSString *event;
10 |
11 | @property (nonatomic, readonly, nullable) NSDictionary *properties;
12 |
13 | - (instancetype)initWithEvent:(NSString *)event
14 | properties:(NSDictionary *_Nullable)properties
15 | context:(NSDictionary *)context
16 | integrations:(NSDictionary *)integrations;
17 |
18 | @end
19 |
20 | NS_ASSUME_NONNULL_END
21 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Integrations/SEGTrackPayload.m:
--------------------------------------------------------------------------------
1 | #import "SEGTrackPayload.h"
2 |
3 |
4 | @implementation SEGTrackPayload
5 |
6 |
7 | - (instancetype)initWithEvent:(NSString *)event
8 | properties:(NSDictionary *)properties
9 | context:(NSDictionary *)context
10 | integrations:(NSDictionary *)integrations
11 | {
12 | if (self = [super initWithContext:context integrations:integrations]) {
13 | _event = [event copy];
14 | _properties = [properties copy];
15 | }
16 | return self;
17 | }
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/NSData+SEGGZIP.h:
--------------------------------------------------------------------------------
1 | //
2 | // GZIP.h
3 | //
4 | // Version 1.1.1
5 | //
6 | // Created by Nick Lockwood on 03/06/2012.
7 | // Copyright (C) 2012 Charcoal Design
8 | //
9 | // Distributed under the permissive zlib License
10 | // Get the latest version from here:
11 | //
12 | // https://github.com/nicklockwood/GZIP
13 | //
14 | // This software is provided 'as-is', without any express or implied
15 | // warranty. In no event will the authors be held liable for any damages
16 | // arising from the use of this software.
17 | //
18 | // Permission is granted to anyone to use this software for any purpose,
19 | // including commercial applications, and to alter it and redistribute it
20 | // freely, subject to the following restrictions:
21 | //
22 | // 1. The origin of this software must not be misrepresented; you must not
23 | // claim that you wrote the original software. If you use this software
24 | // in a product, an acknowledgment in the product documentation would be
25 | // appreciated but is not required.
26 | //
27 | // 2. Altered source versions must be plainly marked as such, and must not be
28 | // misrepresented as being the original software.
29 | //
30 | // 3. This notice may not be removed or altered from any source distribution.
31 | //
32 |
33 |
34 | #import
35 |
36 | extern void *_Nullable seg_libzOpen(void);
37 |
38 |
39 | @interface NSData (GZIP)
40 |
41 | - (nullable NSData *)seg_gzippedData;
42 | - (BOOL)seg_isGzippedData;
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/NSData+SEGGZIP.m:
--------------------------------------------------------------------------------
1 | //
2 | // GZIP.m
3 | //
4 | // Version 1.1.1
5 | //
6 | // Created by Nick Lockwood on 03/06/2012.
7 | // Copyright (C) 2012 Charcoal Design
8 | //
9 | // Distributed under the permissive zlib License
10 | // Get the latest version from here:
11 | //
12 | // https://github.com/nicklockwood/GZIP
13 | //
14 | // This software is provided 'as-is', without any express or implied
15 | // warranty. In no event will the authors be held liable for any damages
16 | // arising from the use of this software.
17 | //
18 | // Permission is granted to anyone to use this software for any purpose,
19 | // including commercial applications, and to alter it and redistribute it
20 | // freely, subject to the following restrictions:
21 | //
22 | // 1. The origin of this software must not be misrepresented; you must not
23 | // claim that you wrote the original software. If you use this software
24 | // in a product, an acknowledgment in the product documentation would be
25 | // appreciated but is not required.
26 | //
27 | // 2. Altered source versions must be plainly marked as such, and must not be
28 | // misrepresented as being the original software.
29 | //
30 | // 3. This notice may not be removed or altered from any source distribution.
31 | //
32 |
33 |
34 | #import "NSData+SEGGZIP.h"
35 | #import
36 | #import
37 |
38 |
39 | #pragma clang diagnostic ignored "-Wcast-qual"
40 |
41 | void *_Nullable seg_libzOpen()
42 | {
43 | static void *libz;
44 | static dispatch_once_t onceToken;
45 | dispatch_once(&onceToken, ^{
46 | libz = dlopen("/usr/lib/libz.dylib", RTLD_LAZY);
47 | });
48 | return libz;
49 | }
50 |
51 |
52 | @implementation NSData (GZIP)
53 |
54 | - (NSData *)seg_gzippedDataWithCompressionLevel:(float)level
55 | {
56 | if (self.length == 0 || [self seg_isGzippedData]) {
57 | return self;
58 | }
59 |
60 | void *libz = seg_libzOpen();
61 | int (*deflateInit2_)(z_streamp, int, int, int, int, int, const char *, int) =
62 | (int (*)(z_streamp, int, int, int, int, int, const char *, int))dlsym(libz, "deflateInit2_");
63 | int (*deflate)(z_streamp, int) = (int (*)(z_streamp, int))dlsym(libz, "deflate");
64 | int (*deflateEnd)(z_streamp) = (int (*)(z_streamp))dlsym(libz, "deflateEnd");
65 |
66 | z_stream stream;
67 | stream.zalloc = Z_NULL;
68 | stream.zfree = Z_NULL;
69 | stream.opaque = Z_NULL;
70 | stream.avail_in = (uint)self.length;
71 | stream.next_in = (Bytef *)(void *)self.bytes;
72 | stream.total_out = 0;
73 | stream.avail_out = 0;
74 |
75 | static const NSUInteger ChunkSize = 16384;
76 |
77 | NSMutableData *output = nil;
78 | int compression = (level < 0.0f) ? Z_DEFAULT_COMPRESSION : (int)(roundf(level * 9));
79 | if (deflateInit2(&stream, compression, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) == Z_OK) {
80 | output = [NSMutableData dataWithLength:ChunkSize];
81 | while (stream.avail_out == 0) {
82 | if (stream.total_out >= output.length) {
83 | output.length += ChunkSize;
84 | }
85 | stream.next_out = (uint8_t *)output.mutableBytes + stream.total_out;
86 | stream.avail_out = (uInt)(output.length - stream.total_out);
87 | deflate(&stream, Z_FINISH);
88 | }
89 | deflateEnd(&stream);
90 | output.length = stream.total_out;
91 | }
92 |
93 | return output;
94 | }
95 |
96 | - (NSData *)seg_gzippedData
97 | {
98 | return [self seg_gzippedDataWithCompressionLevel:-1.0f];
99 | }
100 |
101 | - (BOOL)seg_isGzippedData
102 | {
103 | const UInt8 *bytes = (const UInt8 *)self.bytes;
104 | return (self.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b);
105 | }
106 |
107 | @end
108 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGAnalyticsUtils.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | NS_ASSUME_NONNULL_BEGIN
5 |
6 | NSString *GenerateUUIDString(void);
7 |
8 | // Date Utils
9 | NSString *iso8601FormattedString(NSDate *date);
10 |
11 | // Async Utils
12 | dispatch_queue_t seg_dispatch_queue_create_specific(const char *label,
13 | dispatch_queue_attr_t _Nullable attr);
14 | BOOL seg_dispatch_is_on_specific_queue(dispatch_queue_t queue);
15 | void seg_dispatch_specific(dispatch_queue_t queue, dispatch_block_t block,
16 | BOOL waitForCompletion);
17 | void seg_dispatch_specific_async(dispatch_queue_t queue,
18 | dispatch_block_t block);
19 | void seg_dispatch_specific_sync(dispatch_queue_t queue, dispatch_block_t block);
20 |
21 | // Logging
22 |
23 | void SEGSetShowDebugLogs(BOOL showDebugLogs);
24 | void SEGLog(NSString *format, ...);
25 |
26 | // JSON Utils
27 |
28 | JSON_DICT SEGCoerceDictionary(NSDictionary *_Nullable dict);
29 |
30 | NSString *_Nullable SEGIDFA(void);
31 |
32 | NSString *SEGEventNameForScreenTitle(NSString *title);
33 |
34 | NS_ASSUME_NONNULL_END
35 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGAnalyticsUtils.m:
--------------------------------------------------------------------------------
1 | #import "SEGAnalyticsUtils.h"
2 | #import
3 |
4 | static BOOL kAnalyticsLoggerShowLogs = NO;
5 |
6 | NSString *GenerateUUIDString()
7 | {
8 | CFUUIDRef theUUID = CFUUIDCreate(NULL);
9 | NSString *UUIDString = (__bridge_transfer NSString *)CFUUIDCreateString(NULL, theUUID);
10 | CFRelease(theUUID);
11 | return UUIDString;
12 | }
13 |
14 | // Date Utils
15 | NSString *iso8601FormattedString(NSDate *date)
16 | {
17 | static NSDateFormatter *dateFormatter;
18 | static dispatch_once_t onceToken;
19 | dispatch_once(&onceToken, ^{
20 | dateFormatter = [[NSDateFormatter alloc] init];
21 | dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
22 | dateFormatter.dateFormat = @"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSS'Z'";
23 | dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
24 | });
25 | return [dateFormatter stringFromDate:date];
26 | }
27 |
28 | // Async Utils
29 | dispatch_queue_t
30 | seg_dispatch_queue_create_specific(const char *label,
31 | dispatch_queue_attr_t attr)
32 | {
33 | dispatch_queue_t queue = dispatch_queue_create(label, attr);
34 | dispatch_queue_set_specific(queue, (__bridge const void *)queue,
35 | (__bridge void *)queue, NULL);
36 | return queue;
37 | }
38 |
39 | BOOL seg_dispatch_is_on_specific_queue(dispatch_queue_t queue)
40 | {
41 | return dispatch_get_specific((__bridge const void *)queue) != NULL;
42 | }
43 |
44 | void seg_dispatch_specific(dispatch_queue_t queue, dispatch_block_t block,
45 | BOOL waitForCompletion)
46 | {
47 | dispatch_block_t autoreleasing_block = ^{
48 | @autoreleasepool
49 | {
50 | block();
51 | }
52 | };
53 | if (dispatch_get_specific((__bridge const void *)queue)) {
54 | autoreleasing_block();
55 | } else if (waitForCompletion) {
56 | dispatch_sync(queue, autoreleasing_block);
57 | } else {
58 | dispatch_async(queue, autoreleasing_block);
59 | }
60 | }
61 |
62 | void seg_dispatch_specific_async(dispatch_queue_t queue,
63 | dispatch_block_t block)
64 | {
65 | seg_dispatch_specific(queue, block, NO);
66 | }
67 |
68 | void seg_dispatch_specific_sync(dispatch_queue_t queue,
69 | dispatch_block_t block)
70 | {
71 | seg_dispatch_specific(queue, block, YES);
72 | }
73 |
74 | // Logging
75 |
76 | void SEGSetShowDebugLogs(BOOL showDebugLogs)
77 | {
78 | kAnalyticsLoggerShowLogs = showDebugLogs;
79 | }
80 |
81 | void SEGLog(NSString *format, ...)
82 | {
83 | if (!kAnalyticsLoggerShowLogs)
84 | return;
85 |
86 | va_list args;
87 | va_start(args, format);
88 | NSLogv(format, args);
89 | va_end(args);
90 | }
91 |
92 | // JSON Utils
93 |
94 | static id SEGCoerceJSONObject(id obj)
95 | {
96 | // Hotfix: Storage format should support NSNull instead
97 | if ([obj isKindOfClass:[NSNull class]]) {
98 | return @"";
99 | }
100 | // if the object is a NSString, NSNumber
101 | // then we're good
102 | if ([obj isKindOfClass:[NSString class]] ||
103 | [obj isKindOfClass:[NSNumber class]]) {
104 | return obj;
105 | }
106 |
107 | if ([obj isKindOfClass:[NSArray class]]) {
108 | NSMutableArray *array = [NSMutableArray array];
109 | for (id i in obj) {
110 | // Hotfix: Storage format should support NSNull instead
111 | if ([i isKindOfClass:[NSNull class]]) {
112 | continue;
113 | }
114 | [array addObject:SEGCoerceJSONObject(i)];
115 | }
116 | return array;
117 | }
118 |
119 | if ([obj isKindOfClass:[NSDictionary class]]) {
120 | NSMutableDictionary *dict = [NSMutableDictionary dictionary];
121 | for (NSString *key in obj) {
122 | // Hotfix for issue where SEGFileStorage uses plist which does NOT support NSNull
123 | // So when `[NSNull null]` gets passed in as track property values the queue serialization fails
124 | if ([obj[key] isKindOfClass:[NSNull class]]) {
125 | continue;
126 | }
127 | if (![key isKindOfClass:[NSString class]])
128 | SEGLog(@"warning: dictionary keys should be strings. got: %@. coercing "
129 | @"to: %@",
130 | [key class], [key description]);
131 | dict[key.description] = SEGCoerceJSONObject(obj[key]);
132 | }
133 | return dict;
134 | }
135 |
136 | if ([obj isKindOfClass:[NSDate class]])
137 | return iso8601FormattedString(obj);
138 |
139 | if ([obj isKindOfClass:[NSURL class]])
140 | return [obj absoluteString];
141 |
142 | // default to sending the object's description
143 | SEGLog(@"warning: dictionary values should be valid json types. got: %@. "
144 | @"coercing to: %@",
145 | [obj class], [obj description]);
146 | return [obj description];
147 | }
148 |
149 | static void AssertDictionaryTypes(id dict)
150 | {
151 | #ifdef DEBUG
152 | assert([dict isKindOfClass:[NSDictionary class]]);
153 | for (id key in dict) {
154 | assert([key isKindOfClass:[NSString class]]);
155 | id value = dict[key];
156 |
157 | assert([value isKindOfClass:[NSString class]] ||
158 | [value isKindOfClass:[NSNumber class]] ||
159 | [value isKindOfClass:[NSNull class]] ||
160 | [value isKindOfClass:[NSArray class]] ||
161 | [value isKindOfClass:[NSDictionary class]] ||
162 | [value isKindOfClass:[NSDate class]] ||
163 | [value isKindOfClass:[NSURL class]]);
164 | }
165 | #endif
166 | }
167 |
168 | NSDictionary *SEGCoerceDictionary(NSDictionary *dict)
169 | {
170 | // make sure that a new dictionary exists even if the input is null
171 | dict = dict ?: @{};
172 | // assert that the proper types are in the dictionary
173 | AssertDictionaryTypes(dict);
174 | // coerce urls, and dates to the proper format
175 | return SEGCoerceJSONObject(dict);
176 | }
177 |
178 | NSString *SEGIDFA()
179 | {
180 | NSString *idForAdvertiser = nil;
181 | Class identifierManager = NSClassFromString(@"ASIdentifierManager");
182 | if (identifierManager) {
183 | SEL sharedManagerSelector = NSSelectorFromString(@"sharedManager");
184 | id sharedManager =
185 | ((id (*)(id, SEL))
186 | [identifierManager methodForSelector:sharedManagerSelector])(
187 | identifierManager, sharedManagerSelector);
188 | SEL advertisingIdentifierSelector =
189 | NSSelectorFromString(@"advertisingIdentifier");
190 | NSUUID *uuid =
191 | ((NSUUID * (*)(id, SEL))
192 | [sharedManager methodForSelector:advertisingIdentifierSelector])(
193 | sharedManager, advertisingIdentifierSelector);
194 | idForAdvertiser = [uuid UUIDString];
195 | }
196 | return idForAdvertiser;
197 | }
198 |
199 | NSString *SEGEventNameForScreenTitle(NSString *title)
200 | {
201 | return [[NSString alloc] initWithFormat:@"Viewed %@ Screen", title];
202 | }
203 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGFileStorage.h:
--------------------------------------------------------------------------------
1 | //
2 | // SEGFileStorage.h
3 | // Analytics
4 | //
5 | // Copyright © 2016 Segment. All rights reserved.
6 | //
7 |
8 | #import
9 | #import "SEGStorage.h"
10 |
11 |
12 | @interface SEGFileStorage : NSObject
13 |
14 | @property (nonatomic, strong, nullable) id crypto;
15 |
16 | - (instancetype _Nonnull)init;
17 | - (instancetype _Nonnull)initWithFolder:(NSURL *_Nonnull)folderURL crypto:(id _Nullable)crypto;
18 |
19 | - (NSURL *_Nonnull)urlForKey:(NSString *_Nonnull)key;
20 |
21 | + (NSURL *_Nullable)applicationSupportDirectoryURL;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGFileStorage.m:
--------------------------------------------------------------------------------
1 | //
2 | // SEGFileStorage.m
3 | // Analytics
4 | //
5 | // Copyright © 2016 Segment. All rights reserved.
6 | //
7 |
8 | #import "SEGUtils.h"
9 | #import "SEGFileStorage.h"
10 | #import "SEGCrypto.h"
11 |
12 |
13 | @interface SEGFileStorage ()
14 |
15 | @property (nonatomic, strong, nonnull) NSURL *folderURL;
16 |
17 | @end
18 |
19 |
20 | @implementation SEGFileStorage
21 |
22 | - (instancetype)init
23 | {
24 | return [self initWithFolder:[SEGFileStorage applicationSupportDirectoryURL] crypto:nil];
25 | }
26 |
27 | - (instancetype)initWithFolder:(NSURL *)folderURL crypto:(id)crypto
28 | {
29 | if (self = [super init]) {
30 | _folderURL = folderURL;
31 | _crypto = crypto;
32 | [self createDirectoryAtURLIfNeeded:folderURL];
33 | return self;
34 | }
35 | return nil;
36 | }
37 |
38 | - (void)removeKey:(NSString *)key
39 | {
40 | NSURL *url = [self urlForKey:key];
41 | NSError *error = nil;
42 | if (![[NSFileManager defaultManager] removeItemAtURL:url error:&error]) {
43 | SEGLog(@"Unable to remove key %@ - error removing file at path %@", key, url);
44 | }
45 | }
46 |
47 | - (void)resetAll
48 | {
49 | NSError *error = nil;
50 | if (![[NSFileManager defaultManager] removeItemAtURL:self.folderURL error:&error]) {
51 | SEGLog(@"ERROR: Unable to reset file storage. Path cannot be removed - %@", self.folderURL.path);
52 | }
53 | [self createDirectoryAtURLIfNeeded:self.folderURL];
54 | }
55 |
56 | - (void)setData:(NSData *)data forKey:(NSString *)key
57 | {
58 | NSURL *url = [self urlForKey:key];
59 | if (self.crypto) {
60 | NSData *encryptedData = [self.crypto encrypt:data];
61 | [encryptedData writeToURL:url atomically:YES];
62 | } else {
63 | [data writeToURL:url atomically:YES];
64 | }
65 |
66 | NSError *error = nil;
67 | if (![url setResourceValue:@YES
68 | forKey:NSURLIsExcludedFromBackupKey
69 | error:&error]) {
70 | SEGLog(@"Error excluding %@ from backup %@", [url lastPathComponent], error);
71 | }
72 | }
73 |
74 | - (NSData *)dataForKey:(NSString *)key
75 | {
76 | NSURL *url = [self urlForKey:key];
77 | NSData *data = [NSData dataWithContentsOfURL:url];
78 | if (!data) {
79 | SEGLog(@"WARNING: No data file for key %@", key);
80 | return nil;
81 | }
82 | if (self.crypto) {
83 | return [self.crypto decrypt:data];
84 | }
85 | return data;
86 | }
87 |
88 | - (NSDictionary *)dictionaryForKey:(NSString *)key
89 | {
90 | return [self plistForKey:key];
91 | }
92 |
93 | - (void)setDictionary:(NSDictionary *)dictionary forKey:(NSString *)key
94 | {
95 | [self setPlist:dictionary forKey:key];
96 | }
97 |
98 | - (NSArray *)arrayForKey:(NSString *)key
99 | {
100 | return [self plistForKey:key];
101 | }
102 |
103 | - (void)setArray:(NSArray *)array forKey:(NSString *)key
104 | {
105 | [self setPlist:array forKey:key];
106 | }
107 |
108 | - (NSString *)stringForKey:(NSString *)key
109 | {
110 | return [self plistForKey:key];
111 | }
112 |
113 | - (void)setString:(NSString *)string forKey:(NSString *)key
114 | {
115 | [self setPlist:string forKey:key];
116 | }
117 |
118 | + (NSURL *)applicationSupportDirectoryURL
119 | {
120 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
121 | NSString *supportPath = [paths firstObject];
122 | return [NSURL fileURLWithPath:supportPath];
123 | }
124 |
125 | - (NSURL *)urlForKey:(NSString *)key
126 | {
127 | return [self.folderURL URLByAppendingPathComponent:key];
128 | }
129 |
130 | #pragma mark - Helpers
131 |
132 | - (id _Nullable)plistForKey:(NSString *)key
133 | {
134 | NSData *data = [self dataForKey:key];
135 | return data ? [self plistFromData:data] : nil;
136 | }
137 |
138 | - (void)setPlist:(id _Nonnull)plist forKey:(NSString *)key
139 | {
140 | NSData *data = [self dataFromPlist:plist];
141 | if (data) {
142 | [self setData:data forKey:key];
143 | }
144 | }
145 |
146 | - (NSData *_Nullable)dataFromPlist:(nonnull id)plist
147 | {
148 | NSError *error = nil;
149 | NSData *data = [NSPropertyListSerialization dataWithPropertyList:plist
150 | format:NSPropertyListXMLFormat_v1_0
151 | options:0
152 | error:&error];
153 | if (error) {
154 | SEGLog(@"Unable to serialize data from plist object", error, plist);
155 | }
156 | return data;
157 | }
158 |
159 | - (id _Nullable)plistFromData:(NSData *_Nonnull)data
160 | {
161 | NSError *error = nil;
162 | id plist = [NSPropertyListSerialization propertyListWithData:data
163 | options:0
164 | format:nil
165 | error:&error];
166 | if (error) {
167 | SEGLog(@"Unable to parse plist from data %@", error);
168 | }
169 | return plist;
170 | }
171 |
172 | - (void)createDirectoryAtURLIfNeeded:(NSURL *)url
173 | {
174 | if (![[NSFileManager defaultManager] fileExistsAtPath:url.path
175 | isDirectory:NULL]) {
176 | NSError *error = nil;
177 | if (![[NSFileManager defaultManager] createDirectoryAtPath:url.path
178 | withIntermediateDirectories:YES
179 | attributes:nil
180 | error:&error]) {
181 | SEGLog(@"error: %@", error.localizedDescription);
182 | }
183 | }
184 | }
185 |
186 | @end
187 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGHTTPClient.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "SEGAnalytics.h"
3 |
4 | // TODO: Make this configurable via SEGAnalyticsConfiguration
5 | // NOTE: `/` at the end kind of screws things up. So don't use it
6 | //#define SEGMENT_API_BASE [NSURL URLWithString:@"https://api-segment-io-5fsaj1xnikhp.runscope.net/v1"]
7 | //#define SEGMENT_CDN_BASE [NSURL URLWithString:@"https://cdn-segment-com-5fsaj1xnikhp.runscope.net/v1"]
8 | //#define MOBILE_SERVICE_BASE [NSURL URLWithString:@"https://mobile--service-segment-com-5fsaj1xnikhp.runscope.net/v1"]
9 | #define SEGMENT_API_BASE [NSURL URLWithString:@"https://api.segment.io/v1"]
10 | #define SEGMENT_CDN_BASE [NSURL URLWithString:@"https://cdn-settings.segment.com/v1"]
11 | #define MOBILE_SERVICE_BASE [NSURL URLWithString:@"https://mobile-service.segment.com/v1"]
12 |
13 | NS_ASSUME_NONNULL_BEGIN
14 |
15 |
16 | @interface SEGHTTPClient : NSObject
17 |
18 | @property (nonatomic, strong) SEGRequestFactory requestFactory;
19 | @property (nonatomic, readonly) NSMutableDictionary *sessionsByWriteKey;
20 | @property (nonatomic, readonly) NSURLSession *genericSession;
21 |
22 | + (SEGRequestFactory)defaultRequestFactory;
23 | + (NSString *)authorizationHeader:(NSString *)writeKey;
24 |
25 | - (instancetype)initWithRequestFactory:(SEGRequestFactory _Nullable)requestFactory;
26 |
27 | /**
28 | * Upload dictionary formatted as per https://segment.com/docs/sources/server/http/#batch.
29 | * This method will convert the dictionary to json, gzip it and upload the data.
30 | * It will respond with retry = YES if the batch should be reuploaded at a later time.
31 | * It will ask to retry for json errors and 3xx/5xx codes, and not retry for 2xx/4xx response codes.
32 | * NOTE: You need to re-dispatch within the completionHandler onto a desired queue to avoid threading issues.
33 | * Completion handlers are called on a dispatch queue internal to SEGHTTPClient.
34 | */
35 | - (NSURLSessionUploadTask *)upload:(JSON_DICT)batch forWriteKey:(NSString *)writeKey completionHandler:(void (^)(BOOL retry))completionHandler;
36 |
37 | - (NSURLSessionDataTask *)settingsForWriteKey:(NSString *)writeKey completionHandler:(void (^)(BOOL success, JSON_DICT _Nullable settings))completionHandler;
38 |
39 | - (NSURLSessionDataTask *)attributionWithWriteKey:(NSString *)writeKey forDevice:(JSON_DICT)context completionHandler:(void (^)(BOOL success, JSON_DICT _Nullable properties))completionHandler;
40 |
41 | @end
42 |
43 | NS_ASSUME_NONNULL_END
44 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGHTTPClient.m:
--------------------------------------------------------------------------------
1 | #import "SEGHTTPClient.h"
2 | #import "NSData+SEGGZIP.h"
3 | #import "SEGAnalyticsUtils.h"
4 |
5 |
6 | @implementation SEGHTTPClient
7 |
8 | + (NSMutableURLRequest * (^)(NSURL *))defaultRequestFactory
9 | {
10 | return ^(NSURL *url) {
11 | return [NSMutableURLRequest requestWithURL:url];
12 | };
13 | }
14 |
15 | + (NSString *)authorizationHeader:(NSString *)writeKey
16 | {
17 | NSString *rawHeader = [writeKey stringByAppendingString:@":"];
18 | NSData *userPasswordData = [rawHeader dataUsingEncoding:NSUTF8StringEncoding];
19 | return [userPasswordData base64EncodedStringWithOptions:0];
20 | }
21 |
22 |
23 | - (instancetype)initWithRequestFactory:(SEGRequestFactory)requestFactory
24 | {
25 | if (self = [self init]) {
26 | if (requestFactory == nil) {
27 | self.requestFactory = [SEGHTTPClient defaultRequestFactory];
28 | } else {
29 | self.requestFactory = requestFactory;
30 | }
31 | _sessionsByWriteKey = [NSMutableDictionary dictionary];
32 | NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
33 | config.HTTPAdditionalHeaders = @{ @"Accept-Encoding" : @"gzip" };
34 | _genericSession = [NSURLSession sessionWithConfiguration:config];
35 | }
36 | return self;
37 | }
38 |
39 | - (NSURLSession *)sessionForWriteKey:(NSString *)writeKey
40 | {
41 | NSURLSession *session = self.sessionsByWriteKey[writeKey];
42 | if (!session) {
43 | NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
44 | config.HTTPAdditionalHeaders = @{
45 | @"Accept-Encoding" : @"gzip",
46 | @"Content-Encoding" : @"gzip",
47 | @"Content-Type" : @"application/json",
48 | @"Authorization" : [@"Basic " stringByAppendingString:[[self class] authorizationHeader:writeKey]],
49 | };
50 | session = [NSURLSession sessionWithConfiguration:config];
51 | self.sessionsByWriteKey[writeKey] = session;
52 | }
53 | return session;
54 | }
55 |
56 | - (void)dealloc
57 | {
58 | for (NSURLSession *session in self.sessionsByWriteKey.allValues) {
59 | [session finishTasksAndInvalidate];
60 | }
61 | [self.genericSession finishTasksAndInvalidate];
62 | }
63 |
64 |
65 | - (NSURLSessionUploadTask *)upload:(NSDictionary *)batch forWriteKey:(NSString *)writeKey completionHandler:(void (^)(BOOL retry))completionHandler
66 | {
67 | // batch = SEGCoerceDictionary(batch);
68 | NSURLSession *session = [self sessionForWriteKey:writeKey];
69 |
70 | NSURL *url = [SEGMENT_API_BASE URLByAppendingPathComponent:@"batch"];
71 | NSMutableURLRequest *request = self.requestFactory(url);
72 |
73 | // This is a workaround for an IOS 8.3 bug that causes Content-Type to be incorrectly set
74 | [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
75 |
76 | [request setHTTPMethod:@"POST"];
77 |
78 | NSError *error = nil;
79 | NSException *exception = nil;
80 | NSData *payload = nil;
81 | @try {
82 | payload = [NSJSONSerialization dataWithJSONObject:batch options:0 error:&error];
83 | }
84 | @catch (NSException *exc) {
85 | exception = exc;
86 | }
87 | if (error || exception) {
88 | SEGLog(@"Error serializing JSON for batch upload %@", error);
89 | completionHandler(NO); // Don't retry this batch.
90 | return nil;
91 | }
92 | NSData *gzippedPayload = [payload seg_gzippedData];
93 |
94 | NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromData:gzippedPayload completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
95 | if (error) {
96 | SEGLog(@"Error uploading request %@.", error);
97 | completionHandler(YES);
98 | return;
99 | }
100 |
101 | NSInteger code = ((NSHTTPURLResponse *)response).statusCode;
102 | if (code < 300) {
103 | // 2xx response codes.
104 | completionHandler(NO);
105 | return;
106 | }
107 | if (code < 400) {
108 | // 3xx response codes.
109 | SEGLog(@"Server responded with unexpected HTTP code %d.", code);
110 | completionHandler(YES);
111 | return;
112 | }
113 | if (code < 500) {
114 | // 4xx response codes.
115 | SEGLog(@"Server rejected payload with HTTP code %d.", code);
116 | completionHandler(NO);
117 | return;
118 | }
119 |
120 | // 5xx response codes.
121 | SEGLog(@"Server error with HTTP code %d.", code);
122 | completionHandler(YES);
123 | }];
124 | [task resume];
125 | return task;
126 | }
127 |
128 | - (NSURLSessionDataTask *)settingsForWriteKey:(NSString *)writeKey completionHandler:(void (^)(BOOL success, JSON_DICT _Nullable settings))completionHandler
129 | {
130 | NSURLSession *session = self.genericSession;
131 |
132 | NSURL *url = [SEGMENT_CDN_BASE URLByAppendingPathComponent:[NSString stringWithFormat:@"/projects/%@/settings", writeKey]];
133 | NSMutableURLRequest *request = self.requestFactory(url);
134 | [request setHTTPMethod:@"GET"];
135 |
136 | NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
137 | if (error != nil) {
138 | SEGLog(@"Error fetching settings %@.", error);
139 | completionHandler(NO, nil);
140 | return;
141 | }
142 |
143 | NSInteger code = ((NSHTTPURLResponse *)response).statusCode;
144 | if (code > 300) {
145 | SEGLog(@"Server responded with unexpected HTTP code %d.", code);
146 | completionHandler(NO, nil);
147 | return;
148 | }
149 |
150 | NSError *jsonError = nil;
151 | id responseJson = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
152 | if (jsonError != nil) {
153 | SEGLog(@"Error deserializing response body %@.", jsonError);
154 | completionHandler(NO, nil);
155 | return;
156 | }
157 |
158 | completionHandler(YES, responseJson);
159 | }];
160 | [task resume];
161 | return task;
162 | }
163 |
164 | - (NSURLSessionDataTask *)attributionWithWriteKey:(NSString *)writeKey forDevice:(JSON_DICT)context completionHandler:(void (^)(BOOL success, JSON_DICT _Nullable properties))completionHandler;
165 |
166 | {
167 | NSURLSession *session = [self sessionForWriteKey:writeKey];
168 |
169 | NSURL *url = [MOBILE_SERVICE_BASE URLByAppendingPathComponent:@"/attribution"];
170 | NSMutableURLRequest *request = self.requestFactory(url);
171 | [request setHTTPMethod:@"POST"];
172 |
173 | NSError *error = nil;
174 | NSException *exception = nil;
175 | NSData *payload = nil;
176 | @try {
177 | payload = [NSJSONSerialization dataWithJSONObject:context options:0 error:&error];
178 | }
179 | @catch (NSException *exc) {
180 | exception = exc;
181 | }
182 | if (error || exception) {
183 | SEGLog(@"Error serializing context to JSON %@", error);
184 | completionHandler(NO, nil);
185 | return nil;
186 | }
187 | NSData *gzippedPayload = [payload seg_gzippedData];
188 |
189 | NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromData:gzippedPayload completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
190 | if (error) {
191 | SEGLog(@"Error making request %@.", error);
192 | completionHandler(NO, nil);
193 | return;
194 | }
195 |
196 | NSInteger code = ((NSHTTPURLResponse *)response).statusCode;
197 | if (code > 300) {
198 | SEGLog(@"Server responded with unexpected HTTP code %d.", code);
199 | completionHandler(NO, nil);
200 | return;
201 | }
202 |
203 | NSError *jsonError = nil;
204 | id responseJson = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
205 | if (jsonError != nil) {
206 | SEGLog(@"Error deserializing response body %@.", jsonError);
207 | completionHandler(NO, nil);
208 | return;
209 | }
210 |
211 | completionHandler(YES, responseJson);
212 | }];
213 | [task resume];
214 | return task;
215 | }
216 |
217 | @end
218 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGSegmentIntegration.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "SEGIntegration.h"
3 | #import "SEGHTTPClient.h"
4 | #import "SEGStorage.h"
5 |
6 | NS_ASSUME_NONNULL_BEGIN
7 |
8 | extern NSString *const SEGSegmentDidSendRequestNotification;
9 | extern NSString *const SEGSegmentRequestDidSucceedNotification;
10 | extern NSString *const SEGSegmentRequestDidFailNotification;
11 |
12 |
13 | @interface SEGSegmentIntegration : NSObject
14 |
15 | - (id)initWithAnalytics:(SEGAnalytics *)analytics httpClient:(SEGHTTPClient *)httpClient storage:(id)storage;
16 |
17 | @end
18 |
19 | NS_ASSUME_NONNULL_END
20 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGSegmentIntegrationFactory.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "SEGIntegrationFactory.h"
3 | #import "SEGHTTPClient.h"
4 | #import "SEGStorage.h"
5 |
6 | NS_ASSUME_NONNULL_BEGIN
7 |
8 |
9 | @interface SEGSegmentIntegrationFactory : NSObject
10 |
11 | @property (nonatomic, strong) SEGHTTPClient *client;
12 | @property (nonatomic, strong) id storage;
13 |
14 | - (instancetype)initWithHTTPClient:(SEGHTTPClient *)client storage:(id)storage;
15 |
16 | @end
17 |
18 | NS_ASSUME_NONNULL_END
19 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGSegmentIntegrationFactory.m:
--------------------------------------------------------------------------------
1 | #import "SEGSegmentIntegrationFactory.h"
2 | #import "SEGSegmentIntegration.h"
3 |
4 |
5 | @implementation SEGSegmentIntegrationFactory
6 |
7 | - (id)initWithHTTPClient:(SEGHTTPClient *)client storage:(id)storage
8 | {
9 | if (self = [super init]) {
10 | _client = client;
11 | _storage = storage;
12 | }
13 | return self;
14 | }
15 |
16 | - (id)createWithSettings:(NSDictionary *)settings forAnalytics:(SEGAnalytics *)analytics
17 | {
18 | return [[SEGSegmentIntegration alloc] initWithAnalytics:analytics httpClient:self.client storage:self.storage];
19 | }
20 |
21 | - (NSString *)key
22 | {
23 | return @"Segment.io";
24 | }
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGStorage.h:
--------------------------------------------------------------------------------
1 | //
2 | // SEGStorage.h
3 | // Analytics
4 | //
5 | // Copyright © 2016 Segment. All rights reserved.
6 | //
7 |
8 | #import
9 | #import "SEGCrypto.h"
10 |
11 | @protocol SEGStorage
12 |
13 | @property (nonatomic, strong, nullable) id crypto;
14 |
15 | - (void)removeKey:(NSString *_Nonnull)key;
16 | - (void)resetAll;
17 |
18 | - (void)setData:(NSData *_Nonnull)data forKey:(NSString *_Nonnull)key;
19 | - (NSData *_Nullable)dataForKey:(NSString *_Nonnull)key;
20 |
21 | - (void)setDictionary:(NSDictionary *_Nonnull)dictionary forKey:(NSString *_Nonnull)key;
22 | - (NSDictionary *_Nullable)dictionaryForKey:(NSString *_Nonnull)key;
23 |
24 | - (void)setArray:(NSArray *_Nonnull)array forKey:(NSString *_Nonnull)key;
25 | - (NSArray *_Nullable)arrayForKey:(NSString *_Nonnull)key;
26 |
27 | - (void)setString:(NSString *_Nonnull)string forKey:(NSString *_Nonnull)key;
28 | - (NSString *_Nullable)stringForKey:(NSString *_Nonnull)key;
29 |
30 | // Number and Booleans are intentionally omitted at the moment because they are not needed
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGStoreKitTracker.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "SEGAnalytics.h"
4 |
5 | NS_ASSUME_NONNULL_BEGIN
6 |
7 |
8 | @interface SEGStoreKitTracker : NSObject
9 |
10 | + (instancetype)trackTransactionsForAnalytics:(SEGAnalytics *)analytics;
11 |
12 | @end
13 |
14 | NS_ASSUME_NONNULL_END
15 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGStoreKitTracker.m:
--------------------------------------------------------------------------------
1 | #import "SEGStoreKitTracker.h"
2 |
3 |
4 | @interface SEGStoreKitTracker ()
5 |
6 | @property (nonatomic, readonly) SEGAnalytics *analytics;
7 | @property (nonatomic, readonly) NSMutableDictionary *transactions;
8 | @property (nonatomic, readonly) NSMutableDictionary *productRequests;
9 |
10 | @end
11 |
12 |
13 | @implementation SEGStoreKitTracker
14 |
15 | + (instancetype)trackTransactionsForAnalytics:(SEGAnalytics *)analytics
16 | {
17 | return [[SEGStoreKitTracker alloc] initWithAnalytics:analytics];
18 | }
19 |
20 | - (instancetype)initWithAnalytics:(SEGAnalytics *)analytics
21 | {
22 | if (self = [self init]) {
23 | _analytics = analytics;
24 | _productRequests = [NSMutableDictionary dictionaryWithCapacity:1];
25 | _transactions = [NSMutableDictionary dictionaryWithCapacity:1];
26 |
27 | [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
28 | }
29 | return self;
30 | }
31 |
32 | - (void)dealloc
33 | {
34 | [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
35 | }
36 |
37 | #pragma mark - SKPaymentQueue Observer
38 | - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
39 | {
40 | for (SKPaymentTransaction *transaction in transactions) {
41 | if (transaction.transactionState != SKPaymentTransactionStatePurchased) {
42 | continue;
43 | }
44 |
45 | SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:transaction.payment.productIdentifier]];
46 | @synchronized(self)
47 | {
48 | [self.transactions setObject:transaction forKey:transaction.payment.productIdentifier];
49 | [self.productRequests setObject:request forKey:transaction.payment.productIdentifier];
50 | }
51 | request.delegate = self;
52 | [request start];
53 | }
54 | }
55 |
56 | #pragma mark - SKProductsRequest delegate
57 | - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
58 | {
59 | for (SKProduct *product in response.products) {
60 | @synchronized(self)
61 | {
62 | SKPaymentTransaction *transaction = [self.transactions objectForKey:product.productIdentifier];
63 | [self trackTransaction:transaction forProduct:product];
64 | [self.transactions removeObjectForKey:product.productIdentifier];
65 | [self.productRequests removeObjectForKey:product.productIdentifier];
66 | }
67 | }
68 | }
69 |
70 | #pragma mark - Track
71 | - (void)trackTransaction:(SKPaymentTransaction *)transaction forProduct:(SKProduct *)product
72 | {
73 | // it seems the identifier is nil for renewable subscriptions
74 | // see http://stackoverflow.com/questions/14827059/skpaymenttransactions-originaltransaction-transactionreceipt-nil-for-restore-on
75 | // there isn't a spec'd event for this case ( https://segment.com/docs/spec/ecommerce/v2/ ) so ignoring it for now
76 | if (transaction.transactionIdentifier == nil) {
77 | return;
78 | }
79 |
80 | NSString *currency = [product.priceLocale objectForKey:NSLocaleCurrencyCode];
81 |
82 | [self.analytics track:@"Order Completed" properties:@{
83 | @"orderId" : transaction.transactionIdentifier,
84 | @"affiliation" : @"App Store",
85 | @"currency" : currency ?: @"",
86 | @"products" : @[
87 | @{
88 | @"sku" : transaction.transactionIdentifier,
89 | @"quantity" : @(transaction.payment.quantity),
90 | @"productId" : product.productIdentifier ?: @"",
91 | @"price" : product.price ?: @0,
92 | @"name" : product.localizedTitle ?: @"",
93 | }
94 | ]
95 | }];
96 | }
97 |
98 | @end
99 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGUserDefaultsStorage.h:
--------------------------------------------------------------------------------
1 | //
2 | // SEGUserDefaultsStorage.h
3 | // Analytics
4 | //
5 | // Created by Tony Xiao on 8/24/16.
6 | // Copyright © 2016 Segment. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "SEGStorage.h"
11 |
12 |
13 | @interface SEGUserDefaultsStorage : NSObject
14 |
15 | @property (nonatomic, strong, nullable) id crypto;
16 | @property (nonnull, nonatomic, readonly) NSUserDefaults *defaults;
17 | @property (nullable, nonatomic, readonly) NSString *namespacePrefix;
18 |
19 | - (instancetype _Nonnull)initWithDefaults:(NSUserDefaults *_Nonnull)defaults namespacePrefix:(NSString *_Nullable)namespacePrefix crypto:(id _Nullable)crypto;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGUserDefaultsStorage.m:
--------------------------------------------------------------------------------
1 | //
2 | // SEGUserDefaultsStorage.m
3 | // Analytics
4 | //
5 | // Created by Tony Xiao on 8/24/16.
6 | // Copyright © 2016 Segment. All rights reserved.
7 | //
8 |
9 | #import "SEGUtils.h"
10 | #import "SEGUserDefaultsStorage.h"
11 | #import "SEGCrypto.h"
12 |
13 |
14 | @implementation SEGUserDefaultsStorage
15 |
16 | - (instancetype)initWithDefaults:(NSUserDefaults *)defaults namespacePrefix:(NSString *)namespacePrefix crypto:(id)crypto
17 | {
18 | if (self = [super init]) {
19 | _defaults = defaults;
20 | _namespacePrefix = namespacePrefix;
21 | _crypto = crypto;
22 | }
23 | return self;
24 | }
25 |
26 | - (void)removeKey:(NSString *)key
27 | {
28 | [self.defaults removeObjectForKey:[self namespacedKey:key]];
29 | }
30 |
31 | - (void)resetAll
32 | {
33 | // Courtesy of http://stackoverflow.com/questions/6358737/nsuserdefaults-reset
34 | if (!self.namespacePrefix) {
35 | NSString *domainName = [[NSBundle mainBundle] bundleIdentifier];
36 | if (domainName) {
37 | [self.defaults removePersistentDomainForName:domainName];
38 | return;
39 | }
40 | }
41 | for (NSString *key in self.defaults.dictionaryRepresentation.allKeys) {
42 | if (!self.namespacePrefix || [key hasPrefix:self.namespacePrefix]) {
43 | [self.defaults removeObjectForKey:key];
44 | }
45 | }
46 | [self.defaults synchronize];
47 | }
48 |
49 | - (void)setData:(NSData *)data forKey:(NSString *)key
50 | {
51 | key = [self namespacedKey:key];
52 | if (!self.crypto) {
53 | [self.defaults setObject:data forKey:key];
54 | return;
55 | }
56 | NSData *encryptedData = [self.crypto encrypt:data];
57 | [self.defaults setObject:encryptedData forKey:key];
58 | }
59 |
60 | - (NSData *)dataForKey:(NSString *)key
61 | {
62 | key = [self namespacedKey:key];
63 | if (!self.crypto) {
64 | return [self.defaults objectForKey:key];
65 | }
66 | NSData *data = [self.defaults objectForKey:key];
67 | if (!data) {
68 | SEGLog(@"WARNING: No data file for key %@", key);
69 | return nil;
70 | }
71 | return [self.crypto decrypt:data];
72 | }
73 |
74 | - (NSDictionary *)dictionaryForKey:(NSString *)key
75 | {
76 | if (!self.crypto) {
77 | key = [self namespacedKey:key];
78 | return [self.defaults dictionaryForKey:key];
79 | }
80 | return [self plistForKey:key];
81 | }
82 |
83 | - (void)setDictionary:(NSDictionary *)dictionary forKey:(NSString *)key
84 | {
85 | if (!self.crypto) {
86 | key = [self namespacedKey:key];
87 | [self.defaults setObject:dictionary forKey:key];
88 | return;
89 | }
90 | [self setPlist:dictionary forKey:key];
91 | }
92 |
93 | - (NSArray *)arrayForKey:(NSString *)key
94 | {
95 | if (!self.crypto) {
96 | key = [self namespacedKey:key];
97 | return [self.defaults arrayForKey:key];
98 | }
99 | return [self plistForKey:key];
100 | }
101 |
102 | - (void)setArray:(NSArray *)array forKey:(NSString *)key
103 | {
104 | if (!self.crypto) {
105 | key = [self namespacedKey:key];
106 | [self.defaults setObject:array forKey:key];
107 | return;
108 | }
109 | [self setPlist:array forKey:key];
110 | }
111 |
112 | - (NSString *)stringForKey:(NSString *)key
113 | {
114 | if (!self.crypto) {
115 | key = [self namespacedKey:key];
116 | return [self.defaults stringForKey:key];
117 | }
118 | return [self plistForKey:key];
119 | }
120 |
121 | - (void)setString:(NSString *)string forKey:(NSString *)key
122 | {
123 | if (!self.crypto) {
124 | key = [self namespacedKey:key];
125 | [self.defaults setObject:string forKey:key];
126 | return;
127 | }
128 | [self setPlist:string forKey:key];
129 | }
130 |
131 | #pragma mark - Helpers
132 |
133 | - (id _Nullable)plistForKey:(NSString *)key
134 | {
135 | NSData *data = [self dataForKey:key];
136 | return data ? [SEGUtils plistFromData:data] : nil;
137 | }
138 |
139 | - (void)setPlist:(id _Nonnull)plist forKey:(NSString *)key
140 | {
141 | NSData *data = [SEGUtils dataFromPlist:plist];
142 | if (data) {
143 | [self setData:data forKey:key];
144 | }
145 | }
146 |
147 | - (NSString *)namespacedKey:(NSString *)key
148 | {
149 | if (self.namespacePrefix) {
150 | return [NSString stringWithFormat:@"%@.%@", self.namespacePrefix, key];
151 | }
152 | return key;
153 | }
154 |
155 | @end
156 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGUtils.h:
--------------------------------------------------------------------------------
1 | //
2 | // SEGUtils.h
3 | //
4 | //
5 |
6 | #import
7 | #import "SEGAnalyticsUtils.h"
8 |
9 |
10 | @interface SEGUtils : NSObject
11 |
12 | + (NSData *_Nullable)dataFromPlist:(nonnull id)plist;
13 | + (id _Nullable)plistFromData:(NSData *_Nonnull)data;
14 |
15 | + (id _Nullable)traverseJSON:(id _Nullable)object andReplaceWithFilters:(nonnull NSDictionary*)patterns;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/SEGUtils.m:
--------------------------------------------------------------------------------
1 | //
2 | // SEGUtils.m
3 | //
4 | //
5 |
6 | #import "SEGUtils.h"
7 |
8 |
9 | @implementation SEGUtils
10 |
11 | + (NSData *_Nullable)dataFromPlist:(nonnull id)plist
12 | {
13 | NSError *error = nil;
14 | NSData *data = [NSPropertyListSerialization dataWithPropertyList:plist
15 | format:NSPropertyListXMLFormat_v1_0
16 | options:0
17 | error:&error];
18 | if (error) {
19 | SEGLog(@"Unable to serialize data from plist object", error, plist);
20 | }
21 | return data;
22 | }
23 |
24 | + (id _Nullable)plistFromData:(NSData *_Nonnull)data
25 | {
26 | NSError *error = nil;
27 | id plist = [NSPropertyListSerialization propertyListWithData:data
28 | options:0
29 | format:nil
30 | error:&error];
31 | if (error) {
32 | SEGLog(@"Unable to parse plist from data %@", error);
33 | }
34 | return plist;
35 | }
36 |
37 |
38 | +(id)traverseJSON:(id)object andReplaceWithFilters:(NSDictionary*)patterns
39 | {
40 | if (object == nil || object == NSNull.null || [object isKindOfClass:NSNull.class]) {
41 | return object;
42 | }
43 |
44 | if ([object isKindOfClass:NSDictionary.class]) {
45 | NSDictionary* dict = object;
46 | NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:dict.count];
47 |
48 | for (NSString* key in dict.allKeys) {
49 | newDict[key] = [self traverseJSON:dict[key] andReplaceWithFilters:patterns];
50 | }
51 |
52 | return newDict;
53 | }
54 |
55 | if ([object isKindOfClass:NSArray.class]) {
56 | NSArray* array = object;
57 | NSMutableArray* newArray = [NSMutableArray arrayWithCapacity:array.count];
58 |
59 | for (int i = 0; i < array.count; i++) {
60 | newArray[i] = [self traverseJSON:array[i] andReplaceWithFilters:patterns];
61 | }
62 |
63 | return newArray;
64 | }
65 |
66 | if ([object isKindOfClass:NSString.class]) {
67 | NSError* error = nil;
68 | NSMutableString* str = [object mutableCopy];
69 |
70 | for (NSString* pattern in patterns) {
71 | NSRegularExpression* re = [NSRegularExpression regularExpressionWithPattern:pattern
72 | options:0
73 | error:&error];
74 |
75 | if (error) {
76 | @throw error;
77 | }
78 |
79 | NSInteger matches = [re replaceMatchesInString:str
80 | options:0
81 | range:NSMakeRange(0, str.length)
82 | withTemplate:patterns[pattern]];
83 |
84 | if (matches > 0) {
85 | SEGLog(@"%@ Redacted value from action: %@", self, pattern);
86 | }
87 | }
88 |
89 | return str;
90 | }
91 |
92 | return object;
93 | }
94 |
95 | @end
96 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/UIViewController+SEGScreen.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 |
4 | @interface UIViewController (SEGScreen)
5 |
6 | + (void)seg_swizzleViewDidAppear;
7 | + (UIViewController *)seg_topViewController;
8 |
9 | @end
10 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Internal/UIViewController+SEGScreen.m:
--------------------------------------------------------------------------------
1 | #import "UIViewController+SEGScreen.h"
2 | #import
3 | #import "SEGAnalytics.h"
4 | #import "SEGAnalyticsUtils.h"
5 |
6 |
7 | @implementation UIViewController (SEGScreen)
8 |
9 | + (void)seg_swizzleViewDidAppear
10 | {
11 | static dispatch_once_t onceToken;
12 | dispatch_once(&onceToken, ^{
13 | Class class = [self class];
14 |
15 | SEL originalSelector = @selector(viewDidAppear:);
16 | SEL swizzledSelector = @selector(seg_viewDidAppear:);
17 |
18 | Method originalMethod = class_getInstanceMethod(class, originalSelector);
19 | Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
20 |
21 | BOOL didAddMethod =
22 | class_addMethod(class,
23 | originalSelector,
24 | method_getImplementation(swizzledMethod),
25 | method_getTypeEncoding(swizzledMethod));
26 |
27 | if (didAddMethod) {
28 | class_replaceMethod(class,
29 | swizzledSelector,
30 | method_getImplementation(originalMethod),
31 | method_getTypeEncoding(originalMethod));
32 | } else {
33 | method_exchangeImplementations(originalMethod, swizzledMethod);
34 | }
35 | });
36 | }
37 |
38 |
39 | + (UIViewController *)seg_topViewController
40 | {
41 | UIViewController *root = [[SEGAnalytics sharedAnalytics] configuration].application.delegate.window.rootViewController;
42 | return [self seg_topViewController:root];
43 | }
44 |
45 | + (UIViewController *)seg_topViewController:(UIViewController *)rootViewController
46 | {
47 | UIViewController *presentedViewController = rootViewController.presentedViewController;
48 | if (presentedViewController != nil) {
49 | return [self seg_topViewController:presentedViewController];
50 | }
51 |
52 | if ([rootViewController isKindOfClass:[UINavigationController class]]) {
53 | UIViewController *lastViewController = [[(UINavigationController *)rootViewController viewControllers] lastObject];
54 | return [self seg_topViewController:lastViewController];
55 | }
56 |
57 | return rootViewController;
58 | }
59 |
60 | - (void)seg_viewDidAppear:(BOOL)animated
61 | {
62 | UIViewController *top = [[self class] seg_topViewController];
63 | if (!top) {
64 | SEGLog(@"Could not infer screen.");
65 | return;
66 | }
67 |
68 | NSString *name = [top title];
69 | if (!name || name.length == 0) {
70 | name = [[[top class] description] stringByReplacingOccurrencesOfString:@"ViewController" withString:@""];
71 | // Class name could be just "ViewController".
72 | if (name.length == 0) {
73 | SEGLog(@"Could not infer screen name.");
74 | name = @"Unknown";
75 | }
76 | }
77 | [[SEGAnalytics sharedAnalytics] screen:name properties:nil options:nil];
78 |
79 | [self seg_viewDidAppear:animated];
80 | }
81 |
82 | @end
83 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Middlewares/SEGContext.h:
--------------------------------------------------------------------------------
1 | //
2 | // SEGContext.h
3 | // Analytics
4 | //
5 | // Created by Tony Xiao on 9/19/16.
6 | // Copyright © 2016 Segment. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "SEGIntegration.h"
11 |
12 | typedef NS_ENUM(NSInteger, SEGEventType) {
13 | // Should not happen, but default state
14 | SEGEventTypeUndefined,
15 | // Core Tracking Methods
16 | SEGEventTypeIdentify,
17 | SEGEventTypeTrack,
18 | SEGEventTypeScreen,
19 | SEGEventTypeGroup,
20 | SEGEventTypeAlias,
21 |
22 | // General utility
23 | SEGEventTypeReset,
24 | SEGEventTypeFlush,
25 |
26 | // Remote Notification
27 | SEGEventTypeReceivedRemoteNotification,
28 | SEGEventTypeFailedToRegisterForRemoteNotifications,
29 | SEGEventTypeRegisteredForRemoteNotifications,
30 | SEGEventTypeHandleActionWithForRemoteNotification,
31 |
32 | // Application Lifecycle
33 | SEGEventTypeApplicationLifecycle,
34 | // DidFinishLaunching,
35 | // SEGEventTypeApplicationDidEnterBackground,
36 | // SEGEventTypeApplicationWillEnterForeground,
37 | // SEGEventTypeApplicationWillTerminate,
38 | // SEGEventTypeApplicationWillResignActive,
39 | // SEGEventTypeApplicationDidBecomeActive,
40 |
41 | // Misc.
42 | SEGEventTypeContinueUserActivity,
43 | SEGEventTypeOpenURL,
44 |
45 | };
46 |
47 | @class SEGAnalytics;
48 | @protocol SEGMutableContext;
49 |
50 |
51 | @interface SEGContext : NSObject
52 |
53 | // Loopback reference to the top level SEGAnalytics object.
54 | // Not sure if it's a good idea to keep this around in the context.
55 | // since we don't really want people to use it due to the circular
56 | // reference and logic (Thus prefixing with underscore). But
57 | // Right now it is required for integrations to work so I guess we'll leave it in.
58 | @property (nonatomic, readonly, nonnull) SEGAnalytics *_analytics;
59 | @property (nonatomic, readonly) SEGEventType eventType;
60 |
61 | @property (nonatomic, readonly, nullable) NSString *userId;
62 | @property (nonatomic, readonly, nullable) NSString *anonymousId;
63 | @property (nonatomic, readonly, nullable) NSError *error;
64 | @property (nonatomic, readonly, nullable) SEGPayload *payload;
65 | @property (nonatomic, readonly) BOOL debug;
66 |
67 | - (instancetype _Nonnull)initWithAnalytics:(SEGAnalytics *_Nonnull)analytics;
68 |
69 | - (SEGContext *_Nonnull)modify:(void (^_Nonnull)(id _Nonnull ctx))modify;
70 |
71 | @end
72 |
73 | @protocol SEGMutableContext
74 |
75 | @property (nonatomic) SEGEventType eventType;
76 | @property (nonatomic, nullable) NSString *userId;
77 | @property (nonatomic, nullable) NSString *anonymousId;
78 | @property (nonatomic, nullable) SEGPayload *payload;
79 | @property (nonatomic, nullable) NSError *error;
80 | @property (nonatomic) BOOL debug;
81 |
82 | @end
83 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Middlewares/SEGContext.m:
--------------------------------------------------------------------------------
1 | //
2 | // SEGContext.m
3 | // Analytics
4 | //
5 | // Created by Tony Xiao on 9/19/16.
6 | // Copyright © 2016 Segment. All rights reserved.
7 | //
8 |
9 | #import "SEGContext.h"
10 |
11 |
12 | @interface SEGContext ()
13 |
14 | @property (nonatomic) SEGEventType eventType;
15 | @property (nonatomic, nullable) NSString *userId;
16 | @property (nonatomic, nullable) NSString *anonymousId;
17 | @property (nonatomic, nullable) SEGPayload *payload;
18 | @property (nonatomic, nullable) NSError *error;
19 | @property (nonatomic) BOOL debug;
20 |
21 | @end
22 |
23 |
24 | @implementation SEGContext
25 |
26 | - (instancetype)init
27 | {
28 | @throw [NSException exceptionWithName:@"Bad Initization"
29 | reason:@"Please use initWithAnalytics:"
30 | userInfo:nil];
31 | }
32 |
33 | - (instancetype)initWithAnalytics:(SEGAnalytics *)analytics
34 | {
35 | if (self = [super init]) {
36 | __analytics = analytics;
37 | // TODO: Have some other way of indicating the debug flag is on too.
38 | // Also, for logging it'd be damn nice to implement a logging protocol
39 | // such as CocoalumberJack and allow developers to pipe logs to wherever they want
40 | // Of course we wouldn't us depend on it. it'd be like a soft dependency where
41 | // analytics-ios would totally work without it but works even better with it!
42 | #ifdef DEBUG
43 | _debug = YES;
44 | #endif
45 | }
46 | return self;
47 | }
48 |
49 | - (SEGContext *_Nonnull)modify:(void (^_Nonnull)(id _Nonnull ctx))modify
50 | {
51 | // We're also being a bit clever here by implementing SEGContext actually as a mutable
52 | // object but hiding that implementation detail from consumer of the API.
53 | // In production also instead of copying self we simply just return self
54 | // because the net effect is the same anyways. In the end we get a lot of the benefits
55 | // of immutable data structure without the cost of having to allocate and reallocate
56 | // objects over and over again.
57 | SEGContext *context = self.debug ? [self copy] : self;
58 | modify(context);
59 | // TODO: We could probably add some validation here that the newly modified context
60 | // is actualy valid. For example, `eventType` should match `paylaod` class.
61 | // or anonymousId should never be null.
62 | return context;
63 | }
64 |
65 | #pragma mark - NSCopying
66 |
67 | - (id)copyWithZone:(NSZone *)zone
68 | {
69 | SEGContext *ctx = [[SEGContext allocWithZone:zone] initWithAnalytics:self._analytics];
70 | ctx.eventType = self.eventType;
71 | ctx.userId = self.userId;
72 | ctx.anonymousId = self.anonymousId;
73 | ctx.payload = self.payload;
74 | ctx.error = self.error;
75 | ctx.debug = self.debug;
76 | return ctx;
77 | }
78 |
79 | @end
80 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Middlewares/SEGMiddleware.h:
--------------------------------------------------------------------------------
1 | //
2 | // SEGMiddleware.h
3 | // Analytics
4 | //
5 | // Created by Tony Xiao on 9/19/16.
6 | // Copyright © 2016 Segment. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "SEGContext.h"
11 |
12 | typedef void (^SEGMiddlewareNext)(SEGContext *_Nullable newContext);
13 |
14 | @protocol SEGMiddleware
15 | @required
16 |
17 | // NOTE: If you want to hold onto references of context AFTER passing it through to the next
18 | // middleware, you should explicitly create a copy via `[context copy]` to guarantee
19 | // that it does not get changed from underneath you because contexts can be implemented
20 | // as mutable objects under the hood for performance optimization.
21 | // The behavior of keeping reference to a context AFTER passing it to the next middleware
22 | // is strictly undefined.
23 |
24 | // Middleware should **always** call `next`. If the intention is to explicitly filter out
25 | // events from downstream, call `next` with `nil` as the param.
26 | // It's ok to save next callback until a more convenient time, but it should always always be done.
27 | // We'll probably actually add tests to sure it is so.
28 | // TODO: Should we add error as second param to next?
29 | - (void)context:(SEGContext *_Nonnull)context next:(SEGMiddlewareNext _Nonnull)next;
30 |
31 | @end
32 |
33 | typedef void (^SEGMiddlewareBlock)(SEGContext *_Nonnull context, SEGMiddlewareNext _Nonnull next);
34 |
35 |
36 | @interface SEGBlockMiddleware : NSObject
37 |
38 | @property (nonnull, nonatomic, readonly) SEGMiddlewareBlock block;
39 |
40 | - (instancetype _Nonnull)initWithBlock:(SEGMiddlewareBlock _Nonnull)block;
41 |
42 | @end
43 |
44 |
45 | typedef void (^RunMiddlewaresCallback)(BOOL earlyExit, NSArray> *_Nonnull remainingMiddlewares);
46 |
47 | // XXX TODO: Add some tests for SEGMiddlewareRunner
48 | @interface SEGMiddlewareRunner : NSObject
49 |
50 | // While it is certainly technically possible to change middlewares dynamically on the fly. we're explicitly NOT
51 | // gonna support that for now to keep things simple. If there is a real need later we'll see then.
52 | @property (nonnull, nonatomic, readonly) NSArray> *middlewares;
53 |
54 | - (void)run:(SEGContext *_Nonnull)context callback:(RunMiddlewaresCallback _Nullable)callback;
55 |
56 | - (instancetype _Nonnull)initWithMiddlewares:(NSArray> *_Nonnull)middlewares;
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/Middlewares/SEGMiddleware.m:
--------------------------------------------------------------------------------
1 | //
2 | // SEGMiddleware.m
3 | // Analytics
4 | //
5 | // Created by Tony Xiao on 9/19/16.
6 | // Copyright © 2016 Segment. All rights reserved.
7 | //
8 |
9 | #import "SEGUtils.h"
10 | #import "SEGMiddleware.h"
11 |
12 |
13 | @implementation SEGBlockMiddleware
14 |
15 | - (instancetype)initWithBlock:(SEGMiddlewareBlock)block
16 | {
17 | if (self = [super init]) {
18 | _block = block;
19 | }
20 | return self;
21 | }
22 |
23 | - (void)context:(SEGContext *)context next:(SEGMiddlewareNext)next
24 | {
25 | self.block(context, next);
26 | }
27 |
28 | @end
29 |
30 |
31 | @implementation SEGMiddlewareRunner
32 |
33 | - (instancetype)initWithMiddlewares:(NSArray> *_Nonnull)middlewares
34 | {
35 | if (self = [super init]) {
36 | _middlewares = middlewares;
37 | }
38 | return self;
39 | }
40 |
41 | - (void)run:(SEGContext *_Nonnull)context callback:(RunMiddlewaresCallback _Nullable)callback
42 | {
43 | [self runMiddlewares:self.middlewares context:context callback:callback];
44 | }
45 |
46 | // TODO: Maybe rename SEGContext to SEGEvent to be a bit more clear?
47 | // We could also use some sanity check / other types of logging here.
48 | - (void)runMiddlewares:(NSArray> *_Nonnull)middlewares
49 | context:(SEGContext *_Nonnull)context
50 | callback:(RunMiddlewaresCallback _Nullable)callback
51 | {
52 | BOOL earlyExit = context == nil;
53 | if (middlewares.count == 0 || earlyExit) {
54 | if (callback) {
55 | callback(earlyExit, middlewares);
56 | }
57 | return;
58 | }
59 |
60 | [middlewares[0] context:context next:^(SEGContext *_Nullable newContext) {
61 | NSArray *remainingMiddlewares = [middlewares subarrayWithRange:NSMakeRange(1, middlewares.count - 1)];
62 | [self runMiddlewares:remainingMiddlewares context:newContext callback:callback];
63 | }];
64 | }
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/SEGAnalytics.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "SEGIntegrationFactory.h"
3 | #import "SEGCrypto.h"
4 | #import "SEGAnalyticsConfiguration.h"
5 | #import "SEGSerializableValue.h"
6 |
7 | NS_ASSUME_NONNULL_BEGIN
8 |
9 | /**
10 | * This object provides an API for recording analytics.
11 | */
12 | @class SEGAnalyticsConfiguration;
13 |
14 |
15 | @interface SEGAnalytics : NSObject
16 |
17 | /**
18 | * Used by the analytics client to configure various options.
19 | */
20 | @property (nonatomic, strong, readonly) SEGAnalyticsConfiguration *configuration;
21 |
22 | /**
23 | * Setup this analytics client instance.
24 | *
25 | * @param configuration The configuration used to setup the client.
26 | */
27 | - (instancetype)initWithConfiguration:(SEGAnalyticsConfiguration *)configuration;
28 |
29 | /**
30 | * Setup the analytics client.
31 | *
32 | * @param configuration The configuration used to setup the client.
33 | */
34 | + (void)setupWithConfiguration:(SEGAnalyticsConfiguration *)configuration;
35 |
36 | /**
37 | * Enabled/disables debug logging to trace your data going through the SDK.
38 | *
39 | * @param showDebugLogs `YES` to enable logging, `NO` otherwise. `NO` by default.
40 | */
41 | + (void)debug:(BOOL)showDebugLogs;
42 |
43 | /**
44 | * Returns the shared analytics client.
45 | *
46 | * @see -setupWithConfiguration:
47 | */
48 | + (instancetype)sharedAnalytics;
49 |
50 | /*!
51 | @method
52 |
53 | @abstract
54 | Associate a user with their unique ID and record traits about them.
55 |
56 | @param userId A database ID (or email address) for this user. If you don't have a userId
57 | but want to record traits, you should pass nil. For more information on how we
58 | generate the UUID and Apple's policies on IDs, see https://segment.io/libraries/ios#ids
59 |
60 | @param traits A dictionary of traits you know about the user. Things like: email, name, plan, etc.
61 |
62 | @param options A dictionary of options, such as the `@"anonymousId"` key. If no anonymous ID is specified one will be generated for you.
63 |
64 | @discussion
65 | When you learn more about who your user is, you can record that information with identify.
66 |
67 | */
68 | - (void)identify:(NSString *_Nullable)userId traits:(SERIALIZABLE_DICT _Nullable)traits options:(SERIALIZABLE_DICT _Nullable)options;
69 | - (void)identify:(NSString *_Nullable)userId traits:(SERIALIZABLE_DICT _Nullable)traits;
70 | - (void)identify:(NSString *_Nullable)userId;
71 |
72 |
73 | /*!
74 | @method
75 |
76 | @abstract
77 | Record the actions your users perform.
78 |
79 | @param event The name of the event you're tracking. We recommend using human-readable names
80 | like `Played a Song` or `Updated Status`.
81 |
82 | @param properties A dictionary of properties for the event. If the event was 'Added to Shopping Cart', it might
83 | have properties like price, productType, etc.
84 |
85 | @discussion
86 | When a user performs an action in your app, you'll want to track that action for later analysis. Use the event name to say what the user did, and properties to specify any interesting details of the action.
87 |
88 | */
89 | - (void)track:(NSString *)event properties:(SERIALIZABLE_DICT _Nullable)properties options:(SERIALIZABLE_DICT _Nullable)options;
90 | - (void)track:(NSString *)event properties:(SERIALIZABLE_DICT _Nullable)properties;
91 | - (void)track:(NSString *)event;
92 |
93 | /*!
94 | @method
95 |
96 | @abstract
97 | Record the screens or views your users see.
98 |
99 | @param screenTitle The title of the screen being viewed. We recommend using human-readable names
100 | like 'Photo Feed' or 'Completed Purchase Screen'.
101 |
102 | @param properties A dictionary of properties for the screen view event. If the event was 'Added to Shopping Cart',
103 | it might have properties like price, productType, etc.
104 |
105 | @discussion
106 | When a user views a screen in your app, you'll want to record that here. For some tools like Google Analytics and Flurry, screen views are treated specially, and are different from "events" kind of like "page views" on the web. For services that don't treat "screen views" specially, we map "screen" straight to "track" with the same parameters. For example, Mixpanel doesn't treat "screen views" any differently. So a call to "screen" will be tracked as a normal event in Mixpanel, but get sent to Google Analytics and Flurry as a "screen".
107 |
108 | */
109 | - (void)screen:(NSString *)screenTitle properties:(SERIALIZABLE_DICT _Nullable)properties options:(SERIALIZABLE_DICT _Nullable)options;
110 | - (void)screen:(NSString *)screenTitle properties:(SERIALIZABLE_DICT _Nullable)properties;
111 | - (void)screen:(NSString *)screenTitle;
112 |
113 | /*!
114 | @method
115 |
116 | @abstract
117 | Associate a user with a group, organization, company, project, or w/e *you* call them.
118 |
119 | @param groupId A database ID for this group.
120 | @param traits A dictionary of traits you know about the group. Things like: name, employees, etc.
121 |
122 | @discussion
123 | When you learn more about who the group is, you can record that information with group.
124 |
125 | */
126 | - (void)group:(NSString *)groupId traits:(SERIALIZABLE_DICT _Nullable)traits options:(SERIALIZABLE_DICT _Nullable)options;
127 | - (void)group:(NSString *)groupId traits:(SERIALIZABLE_DICT _Nullable)traits;
128 | - (void)group:(NSString *)groupId;
129 |
130 | /*!
131 | @method
132 |
133 | @abstract
134 | Merge two user identities, effectively connecting two sets of user data as one.
135 | This may not be supported by all integrations.
136 |
137 | @param newId The new ID you want to alias the existing ID to. The existing ID will be either the
138 | previousId if you have called identify, or the anonymous ID.
139 |
140 | @discussion
141 | When you learn more about who the group is, you can record that information with group.
142 |
143 | */
144 | - (void)alias:(NSString *)newId options:(SERIALIZABLE_DICT _Nullable)options;
145 | - (void)alias:(NSString *)newId;
146 |
147 | // todo: docs
148 | - (void)receivedRemoteNotification:(NSDictionary *)userInfo;
149 | - (void)failedToRegisterForRemoteNotificationsWithError:(NSError *)error;
150 | - (void)registeredForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
151 | - (void)handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo;
152 | - (void)continueUserActivity:(NSUserActivity *)activity;
153 | - (void)openURL:(NSURL *)url options:(NSDictionary *)options;
154 |
155 | /*!
156 | @method
157 |
158 | @abstract
159 | Trigger an upload of all queued events.
160 |
161 | @discussion
162 | This is useful when you want to force all messages queued on the device to be uploaded. Please note that not all integrations
163 | respond to this method.
164 | */
165 | - (void)flush;
166 |
167 | /*!
168 | @method
169 |
170 | @abstract
171 | Reset any user state that is cached on the device.
172 |
173 | @discussion
174 | This is useful when a user logs out and you want to clear the identity. It will clear any
175 | traits or userId's cached on the device.
176 | */
177 | - (void)reset;
178 |
179 | /*!
180 | @method
181 |
182 | @abstract
183 | Enable the sending of analytics data. Enabled by default.
184 |
185 | @discussion
186 | Occasionally used in conjunction with disable user opt-out handling.
187 | */
188 | - (void)enable;
189 |
190 |
191 | /*!
192 | @method
193 |
194 | @abstract
195 | Completely disable the sending of any analytics data.
196 |
197 | @discussion
198 | If have a way for users to actively or passively (sometimes based on location) opt-out of
199 | analytics data collection, you can use this method to turn off all data collection.
200 | */
201 | - (void)disable;
202 |
203 |
204 | /**
205 | * Version of the library.
206 | */
207 | + (NSString *)version;
208 |
209 | /**
210 | * Returns a dictionary of integrations that are bundled. This is an internal Segment API, and may be removed at any time
211 | * without notice.
212 | */
213 | - (NSDictionary *)bundledIntegrations;
214 |
215 | /** Returns the anonymous ID of the current user. */
216 | - (NSString *)getAnonymousId;
217 |
218 | /** Returns the configuration used to create the analytics client. */
219 | - (SEGAnalyticsConfiguration *)configuration;
220 |
221 |
222 | @end
223 |
224 | NS_ASSUME_NONNULL_END
225 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/SEGAnalyticsConfiguration.h:
--------------------------------------------------------------------------------
1 | //
2 | // SEGIntegrationsManager.h
3 | // Analytics
4 | //
5 | // Created by Tony Xiao on 9/20/16.
6 | // Copyright © 2016 Segment. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @protocol SEGApplicationProtocol
13 | @property (nullable, nonatomic, assign) id delegate;
14 | - (UIBackgroundTaskIdentifier)seg_beginBackgroundTaskWithName:(nullable NSString *)taskName expirationHandler:(void (^__nullable)(void))handler;
15 | - (void)seg_endBackgroundTask:(UIBackgroundTaskIdentifier)identifier;
16 | @end
17 |
18 |
19 | @interface UIApplication (SEGApplicationProtocol)
20 | @end
21 |
22 | typedef NSMutableURLRequest *_Nonnull (^SEGRequestFactory)(NSURL *_Nonnull);
23 |
24 | @protocol SEGIntegrationFactory;
25 | @protocol SEGCrypto;
26 | @protocol SEGMiddleware;
27 |
28 | /**
29 | * This object provides a set of properties to control various policies of the analytics client. Other than `writeKey`, these properties can be changed at any time.
30 | */
31 | @interface SEGAnalyticsConfiguration : NSObject
32 |
33 | /**
34 | * Creates and returns a configuration with default settings and the given write key.
35 | *
36 | * @param writeKey Your project's write key from segment.io.
37 | */
38 | + (_Nonnull instancetype)configurationWithWriteKey:(NSString *_Nonnull)writeKey;
39 |
40 | /**
41 | * Your project's write key from segment.io.
42 | *
43 | * @see +configurationWithWriteKey:
44 | */
45 | @property (nonatomic, copy, readonly, nonnull) NSString *writeKey;
46 |
47 | /**
48 | * Whether the analytics client should use location services.
49 | * If `YES` and the host app hasn't asked for permission to use location services then the user will be presented with an alert view asking to do so. `NO` by default.
50 | * If `YES`, please make sure to add a description for `NSLocationAlwaysUsageDescription` in your `Info.plist` explaining why your app is accessing Location APIs.
51 | */
52 | @property (nonatomic, assign) BOOL shouldUseLocationServices;
53 |
54 | /**
55 | * Whether the analytics client should track advertisting info. `YES` by default.
56 | */
57 | @property (nonatomic, assign) BOOL enableAdvertisingTracking;
58 |
59 | /**
60 | * The number of queued events that the analytics client should flush at. Setting this to `1` will not queue any events and will use more battery. `20` by default.
61 | */
62 | @property (nonatomic, assign) NSUInteger flushAt;
63 |
64 |
65 | /**
66 | * Whether the analytics client should automatically make a track call for application lifecycle events, such as "Application Installed", "Application Updated" and "Application Opened".
67 | */
68 | @property (nonatomic, assign) BOOL trackApplicationLifecycleEvents;
69 |
70 |
71 | /**
72 | * Whether the analytics client should record bluetooth information. If `YES`, please make sure to add a description for `NSBluetoothPeripheralUsageDescription` in your `Info.plist` explaining explaining why your app is accessing Bluetooth APIs. `NO` by default.
73 | */
74 | @property (nonatomic, assign) BOOL shouldUseBluetooth;
75 |
76 | /**
77 | * Whether the analytics client should automatically make a screen call when a view controller is added to a view hierarchy. Because the underlying implementation uses method swizzling, we recommend initializing the analytics client as early as possible (before any screens are displayed), ideally during the Application delegate's applicationDidFinishLaunching method.
78 | */
79 | @property (nonatomic, assign) BOOL recordScreenViews;
80 |
81 | /**
82 | * Whether the analytics client should automatically track in-app purchases from the App Store.
83 | */
84 | @property (nonatomic, assign) BOOL trackInAppPurchases;
85 |
86 | /**
87 | * Whether the analytics client should automatically track push notifications.
88 | */
89 | @property (nonatomic, assign) BOOL trackPushNotifications;
90 |
91 | /**
92 | * Whether the analytics client should automatically track deep links. You'll still need to call the continueUserActivity and openURL methods on the analytics client.
93 | */
94 | @property (nonatomic, assign) BOOL trackDeepLinks;
95 |
96 | /**
97 | * Whether the analytics client should automatically track attribution data from enabled providers using the mobile service.
98 | */
99 | @property (nonatomic, assign) BOOL trackAttributionData;
100 |
101 | /**
102 | * Dictionary indicating the options the app was launched with.
103 | */
104 | @property (nonatomic, strong, nullable) NSDictionary *launchOptions;
105 |
106 | /**
107 | * Set a custom request factory.
108 | */
109 | @property (nonatomic, strong, nullable) SEGRequestFactory requestFactory;
110 |
111 | /**
112 | * Set a custom crypto
113 | */
114 | @property (nonatomic, strong, nullable) id crypto;
115 |
116 | /**
117 | * Set custom middlewares. Will be run before all integrations
118 | */
119 | @property (nonatomic, strong, nullable) NSArray> *middlewares;
120 |
121 | /**
122 | * Register a factory that can be used to create an integration.
123 | */
124 | - (void)use:(id _Nonnull)factory;
125 |
126 | /**
127 | * Leave this nil for iOS extensions, otherwise set to UIApplication.sharedApplication.
128 | */
129 | @property (nonatomic, strong, nullable) id application;
130 |
131 | /**
132 | * A dictionary of filters to redact payloads before they are sent.
133 | * This is an experimental feature that currently only applies to Deep Links.
134 | * It is subject to change to allow for more flexible customizations in the future.
135 | *
136 | * The key of this dictionary should be a regular expression string pattern,
137 | * and the value should be a regular expression substitution template.
138 | *
139 | * By default, this contains a Facebook auth token filter, configured as such:
140 | * @code
141 | * @"(fb\\d+://authorize#access_token=)([^ ]+)": @"$1((redacted/fb-auth-token))"
142 | * @endcode
143 | *
144 | * This will replace any matching occurences to a redacted version:
145 | * @code
146 | * "fb123456789://authorize#access_token=secretsecretsecretsecret&some=data"
147 | * @endcode
148 | *
149 | * Becomes:
150 | * @code
151 | * "fb123456789://authorize#access_token=((redacted/fb-auth-token))"
152 | * @endcode
153 | *
154 | */
155 | @property (nonatomic, strong, nonnull) NSDictionary* payloadFilters;
156 |
157 | @end
158 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/SEGAnalyticsConfiguration.m:
--------------------------------------------------------------------------------
1 | //
2 | // SEGIntegrationsManager.h
3 | // Analytics
4 | //
5 | // Created by Tony Xiao on 9/20/16.
6 | // Copyright © 2016 Segment. All rights reserved.
7 | //
8 |
9 | #import "SEGAnalyticsConfiguration.h"
10 | #import "SEGCrypto.h"
11 |
12 |
13 | @implementation UIApplication (SEGApplicationProtocol)
14 |
15 | - (UIBackgroundTaskIdentifier)seg_beginBackgroundTaskWithName:(nullable NSString *)taskName expirationHandler:(void (^__nullable)(void))handler
16 | {
17 | return [self beginBackgroundTaskWithName:taskName expirationHandler:handler];
18 | }
19 |
20 | - (void)seg_endBackgroundTask:(UIBackgroundTaskIdentifier)identifier
21 | {
22 | [self endBackgroundTask:identifier];
23 | }
24 |
25 | @end
26 |
27 |
28 | @interface SEGAnalyticsConfiguration ()
29 |
30 | @property (nonatomic, copy, readwrite) NSString *writeKey;
31 | @property (nonatomic, strong, readonly) NSMutableArray *factories;
32 |
33 | @end
34 |
35 |
36 | @implementation SEGAnalyticsConfiguration
37 |
38 | + (instancetype)configurationWithWriteKey:(NSString *)writeKey
39 | {
40 | return [[SEGAnalyticsConfiguration alloc] initWithWriteKey:writeKey];
41 | }
42 |
43 | - (instancetype)initWithWriteKey:(NSString *)writeKey
44 | {
45 | if (self = [self init]) {
46 | self.writeKey = writeKey;
47 | }
48 | return self;
49 | }
50 |
51 | - (instancetype)init
52 | {
53 | if (self = [super init]) {
54 | self.shouldUseLocationServices = NO;
55 | self.enableAdvertisingTracking = YES;
56 | self.shouldUseBluetooth = NO;
57 | self.flushAt = 20;
58 | self.payloadFilters = @{
59 | @"(fb\\d+://authorize#access_token=)([^ ]+)": @"$1((redacted/fb-auth-token))"
60 | };
61 | _factories = [NSMutableArray array];
62 | Class applicationClass = NSClassFromString(@"UIApplication");
63 | if (applicationClass) {
64 | #pragma clang diagnostic push
65 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
66 | _application = [applicationClass performSelector:NSSelectorFromString(@"sharedApplication")];
67 | #pragma clang diagnostic pop
68 | }
69 | }
70 | return self;
71 | }
72 |
73 | - (void)use:(id)factory
74 | {
75 | [self.factories addObject:factory];
76 | }
77 |
78 | - (NSString *)description
79 | {
80 | return [NSString stringWithFormat:@"<%p:%@, %@>", self, self.class, [self dictionaryWithValuesForKeys:@[ @"writeKey", @"shouldUseLocationServices", @"flushAt" ]]];
81 | }
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Classes/SEGSerializableValue.h:
--------------------------------------------------------------------------------
1 | //
2 | // SEGSerializableValue.h
3 | // Analytics
4 | //
5 | // Created by Tony Xiao on 11/29/16.
6 | // Copyright © 2016 Segment. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /*
12 | Acceptable dictionary values are
13 | NSString (String);
14 | NSNumber (Int, Float, Bool);
15 | NSNull
16 | NSDate => ISO8601 String
17 | NSURL => absoluteURL String
18 | NSArray of the above
19 | NSDictionary of the above
20 | */
21 | #define SERIALIZABLE_DICT NSDictionary *
22 |
23 | /*
24 | Acceptable dictionary values are
25 | NSString (String);
26 | NSNumber (Int, Float, Bool);
27 | NSNull
28 | NSArray of the above
29 | NSDictionary of the above
30 | */
31 | #define JSON_DICT NSDictionary *
32 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/Analytics/Vendor/SEGReachability.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Tony Million.
3 | All rights reserved.
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 | 1. Redistributions of source code must retain the above copyright notice, this
7 | list of conditions and the following disclaimer.
8 | 2. Redistributions in binary form must reproduce the above copyright notice,
9 | this list of conditions and the following disclaimer in the documentation
10 | and/or other materials provided with the distribution.
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
12 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
15 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
16 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
17 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
18 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
19 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
20 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21 | POSSIBILITY OF SUCH DAMAGE.
22 | */
23 |
24 | #import
25 | #import
26 |
27 | /**
28 | * Does ARC support GCD objects?
29 | * It does if the minimum deployment target is iOS 6+ or Mac OS X 8+
30 | *
31 | * @see http://opensource.apple.com/source/libdispatch/libdispatch-228.18/os/object.h
32 | **/
33 | #if OS_OBJECT_USE_OBJC
34 | #define NEEDS_DISPATCH_RETAIN_RELEASE 0
35 | #else
36 | #define NEEDS_DISPATCH_RETAIN_RELEASE 1
37 | #endif
38 |
39 | /**
40 | * Create NS_ENUM macro if it does not exist on the targeted version of iOS or OS X.
41 | *
42 | * @see http://nshipster.com/ns_enum-ns_options/
43 | **/
44 | #ifndef NS_ENUM
45 | #define NS_ENUM(_type, _name) \
46 | enum _name : _type _name; \
47 | enum _name : _type
48 | #endif
49 |
50 | NS_ASSUME_NONNULL_BEGIN
51 |
52 | extern NSString *const kSEGReachabilityChangedNotification;
53 |
54 | typedef NS_ENUM(NSInteger, SEGNetworkStatus) {
55 | // Apple NetworkStatus Compatible Names.
56 | SEGNotReachable = 0,
57 | SEGReachableViaWiFi = 2,
58 | SEGReachableViaWWAN = 1
59 | };
60 |
61 | @class SEGReachability;
62 |
63 | typedef void (^SEGNetworkReachable)(SEGReachability *reachability);
64 | typedef void (^SEGNetworkUnreachable)(SEGReachability *reachability);
65 |
66 |
67 | @interface SEGReachability : NSObject
68 |
69 | @property (nonatomic, copy, nullable) SEGNetworkReachable reachableBlock;
70 | @property (nonatomic, copy, nullable) SEGNetworkUnreachable unreachableBlock;
71 |
72 |
73 | @property (nonatomic, assign) BOOL reachableOnWWAN;
74 |
75 | + (SEGReachability *_Nullable)reachabilityWithHostname:(NSString *)hostname;
76 | + (SEGReachability *_Nullable)reachabilityForInternetConnection;
77 | + (SEGReachability *_Nullable)reachabilityForLocalWiFi;
78 |
79 | - (SEGReachability *)initWithReachabilityRef:(SCNetworkReachabilityRef)ref;
80 |
81 | - (BOOL)startNotifier;
82 | - (void)stopNotifier;
83 |
84 | - (BOOL)isReachable;
85 | - (BOOL)isReachableViaWWAN;
86 | - (BOOL)isReachableViaWiFi;
87 |
88 | // WWAN may be available, but not active until a connection has been established.
89 | // WiFi may require a connection for VPN on Demand.
90 | - (BOOL)isConnectionRequired; // Identical DDG variant.
91 | - (BOOL)connectionRequired; // Apple's routine.
92 | // Dynamic, on demand connection?
93 | - (BOOL)isConnectionOnDemand;
94 | // Is user intervention required?
95 | - (BOOL)isInterventionRequired;
96 |
97 | - (SEGNetworkStatus)currentReachabilityStatus;
98 | - (SCNetworkReachabilityFlags)reachabilityFlags;
99 | - (NSString *)currentReachabilityString;
100 | - (NSString *)currentReachabilityFlags;
101 |
102 | @end
103 |
104 | NS_ASSUME_NONNULL_END
105 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Segment.io, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Analytics/README.md:
--------------------------------------------------------------------------------
1 | # Analytics
2 | [](https://circleci.com/gh/segmentio/analytics-ios)
3 | [](https://cocoapods.org//pods/Analytics)
4 | [](http://cocoapods.org/pods/Analytics)
5 | [](https://codecov.io/gh/segmentio/analytics-ios)
6 |
7 | analytics-ios is an iOS client for Segment.
8 |
9 | Special thanks to [Tony Xiao](https://github.com/tonyxiao), [Lee Hasiuk](https://github.com/lhasiuk) and [Cristian Bica](https://github.com/cristianbica) for their contributions to the library!
10 |
11 | ## Installation
12 |
13 | Analytics is available through [CocoaPods](http://cocoapods.org) and [Carthage](https://github.com/Carthage/Carthage).
14 |
15 | ### CocoaPods
16 |
17 | ```ruby
18 | pod "Analytics", "3.6.0"
19 | ```
20 |
21 | ### Carthage
22 |
23 | ```
24 | github "segmentio/analytics-ios"
25 | ```
26 |
27 | ## Quickstart
28 |
29 | Refer to the Quickstart documentation at [https://segment.com/docs/libraries/ios/quickstart](https://segment.com/docs/libraries/ios/quickstart/).
30 |
31 | ## Documentation
32 |
33 | More detailed documentation is available at [https://segment.com/docs/libraries/ios](https://segment.com/docs/libraries/ios/).
34 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Analytics (3.6.10)
3 |
4 | DEPENDENCIES:
5 | - Analytics (= 3.6.10)
6 |
7 | SPEC REPOS:
8 | https://github.com/cocoapods/specs.git:
9 | - Analytics
10 |
11 | SPEC CHECKSUMS:
12 | Analytics: 63744ad4afa65c3bcdcdb7a94b62515bde5b3900
13 |
14 | PODFILE CHECKSUM: 1078e7b12a3b5e456d114d57af4de4aca03fb029
15 |
16 | COCOAPODS: 1.6.0
17 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Analytics/Analytics-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 3.6.10
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Analytics/Analytics-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Analytics : NSObject
3 | @end
4 | @implementation PodsDummy_Analytics
5 | @end
6 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Analytics/Analytics-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Analytics/Analytics-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 | #import "SEGAES256Crypto.h"
14 | #import "SEGCrypto.h"
15 | #import "SEGAliasPayload.h"
16 | #import "SEGGroupPayload.h"
17 | #import "SEGIdentifyPayload.h"
18 | #import "SEGIntegration.h"
19 | #import "SEGIntegrationFactory.h"
20 | #import "SEGIntegrationsManager.h"
21 | #import "SEGPayload.h"
22 | #import "SEGScreenPayload.h"
23 | #import "SEGTrackPayload.h"
24 | #import "NSData+SEGGZIP.h"
25 | #import "SEGAnalyticsUtils.h"
26 | #import "SEGFileStorage.h"
27 | #import "SEGHTTPClient.h"
28 | #import "SEGSegmentIntegration.h"
29 | #import "SEGSegmentIntegrationFactory.h"
30 | #import "SEGStorage.h"
31 | #import "SEGStoreKitTracker.h"
32 | #import "SEGUserDefaultsStorage.h"
33 | #import "SEGUtils.h"
34 | #import "UIViewController+SEGScreen.h"
35 | #import "SEGContext.h"
36 | #import "SEGMiddleware.h"
37 | #import "SEGAnalytics.h"
38 | #import "SEGAnalyticsConfiguration.h"
39 | #import "SEGSerializableValue.h"
40 | #import "SEGReachability.h"
41 |
42 | FOUNDATION_EXPORT double AnalyticsVersionNumber;
43 | FOUNDATION_EXPORT const unsigned char AnalyticsVersionString[];
44 |
45 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Analytics/Analytics.modulemap:
--------------------------------------------------------------------------------
1 | framework module Analytics {
2 | umbrella header "Analytics-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Analytics/Analytics.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Analytics
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | PODS_BUILD_DIR = ${BUILD_DIR}
4 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
5 | PODS_ROOT = ${SRCROOT}
6 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Analytics
7 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
8 | SKIP_INSTALL = YES
9 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Pods-AnalyticsSwiftExample/Pods-AnalyticsSwiftExample-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Pods-AnalyticsSwiftExample/Pods-AnalyticsSwiftExample-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## Analytics
5 |
6 | The MIT License (MIT)
7 |
8 | Copyright (c) 2016 Segment.io, Inc.
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | The above copyright notice and this permission notice shall be included in all
18 | copies or substantial portions of the Software.
19 |
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | SOFTWARE.
27 |
28 | Generated by CocoaPods - https://cocoapods.org
29 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Pods-AnalyticsSwiftExample/Pods-AnalyticsSwiftExample-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | The MIT License (MIT)
18 |
19 | Copyright (c) 2016 Segment.io, Inc.
20 |
21 | Permission is hereby granted, free of charge, to any person obtaining a copy
22 | of this software and associated documentation files (the "Software"), to deal
23 | in the Software without restriction, including without limitation the rights
24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25 | copies of the Software, and to permit persons to whom the Software is
26 | furnished to do so, subject to the following conditions:
27 |
28 | The above copyright notice and this permission notice shall be included in all
29 | copies or substantial portions of the Software.
30 |
31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37 | SOFTWARE.
38 |
39 | License
40 | MIT
41 | Title
42 | Analytics
43 | Type
44 | PSGroupSpecifier
45 |
46 |
47 | FooterText
48 | Generated by CocoaPods - https://cocoapods.org
49 | Title
50 |
51 | Type
52 | PSGroupSpecifier
53 |
54 |
55 | StringsTable
56 | Acknowledgements
57 | Title
58 | Acknowledgements
59 |
60 |
61 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Pods-AnalyticsSwiftExample/Pods-AnalyticsSwiftExample-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_AnalyticsSwiftExample : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_AnalyticsSwiftExample
5 | @end
6 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Pods-AnalyticsSwiftExample/Pods-AnalyticsSwiftExample-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | function on_error {
7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 | }
9 | trap 'on_error $LINENO' ERR
10 |
11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
13 | # frameworks to, so exit 0 (signalling the script phase was successful).
14 | exit 0
15 | fi
16 |
17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
19 |
20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
22 |
23 | # Used as a return value for each invocation of `strip_invalid_archs` function.
24 | STRIP_BINARY_RETVAL=0
25 |
26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
29 |
30 | # Copies and strips a vendored framework
31 | install_framework()
32 | {
33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
34 | local source="${BUILT_PRODUCTS_DIR}/$1"
35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
37 | elif [ -r "$1" ]; then
38 | local source="$1"
39 | fi
40 |
41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
42 |
43 | if [ -L "${source}" ]; then
44 | echo "Symlinked..."
45 | source="$(readlink "${source}")"
46 | fi
47 |
48 | # Use filter instead of exclude so missing patterns don't throw errors.
49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
51 |
52 | local basename
53 | basename="$(basename -s .framework "$1")"
54 | binary="${destination}/${basename}.framework/${basename}"
55 |
56 | if ! [ -r "$binary" ]; then
57 | binary="${destination}/${basename}"
58 | elif [ -L "${binary}" ]; then
59 | echo "Destination binary is symlinked..."
60 | dirname="$(dirname "${binary}")"
61 | binary="${dirname}/$(readlink "${binary}")"
62 | fi
63 |
64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
66 | strip_invalid_archs "$binary"
67 | fi
68 |
69 | # Resign the code if required by the build settings to avoid unstable apps
70 | code_sign_if_enabled "${destination}/$(basename "$1")"
71 |
72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
74 | local swift_runtime_libs
75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
76 | for lib in $swift_runtime_libs; do
77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
79 | code_sign_if_enabled "${destination}/${lib}"
80 | done
81 | fi
82 | }
83 |
84 | # Copies and strips a vendored dSYM
85 | install_dsym() {
86 | local source="$1"
87 | if [ -r "$source" ]; then
88 | # Copy the dSYM into a the targets temp dir.
89 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
90 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
91 |
92 | local basename
93 | basename="$(basename -s .framework.dSYM "$source")"
94 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
95 |
96 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
97 | if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then
98 | strip_invalid_archs "$binary"
99 | fi
100 |
101 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
102 | # Move the stripped file into its final destination.
103 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
104 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
105 | else
106 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
107 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
108 | fi
109 | fi
110 | }
111 |
112 | # Signs a framework with the provided identity
113 | code_sign_if_enabled() {
114 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
115 | # Use the current code_sign_identity
116 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
117 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
118 |
119 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
120 | code_sign_cmd="$code_sign_cmd &"
121 | fi
122 | echo "$code_sign_cmd"
123 | eval "$code_sign_cmd"
124 | fi
125 | }
126 |
127 | # Strip invalid architectures
128 | strip_invalid_archs() {
129 | binary="$1"
130 | # Get architectures for current target binary
131 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
132 | # Intersect them with the architectures we are building for
133 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
134 | # If there are no archs supported by this binary then warn the user
135 | if [[ -z "$intersected_archs" ]]; then
136 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
137 | STRIP_BINARY_RETVAL=0
138 | return
139 | fi
140 | stripped=""
141 | for arch in $binary_archs; do
142 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
143 | # Strip non-valid architectures in-place
144 | lipo -remove "$arch" -output "$binary" "$binary"
145 | stripped="$stripped $arch"
146 | fi
147 | done
148 | if [[ "$stripped" ]]; then
149 | echo "Stripped $binary of architectures:$stripped"
150 | fi
151 | STRIP_BINARY_RETVAL=1
152 | }
153 |
154 |
155 | if [[ "$CONFIGURATION" == "Debug" ]]; then
156 | install_framework "${BUILT_PRODUCTS_DIR}/Analytics/Analytics.framework"
157 | fi
158 | if [[ "$CONFIGURATION" == "Release" ]]; then
159 | install_framework "${BUILT_PRODUCTS_DIR}/Analytics/Analytics.framework"
160 | fi
161 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
162 | wait
163 | fi
164 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Pods-AnalyticsSwiftExample/Pods-AnalyticsSwiftExample-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_AnalyticsSwiftExampleVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_AnalyticsSwiftExampleVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Pods-AnalyticsSwiftExample/Pods-AnalyticsSwiftExample.debug.xcconfig:
--------------------------------------------------------------------------------
1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Analytics"
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Analytics/Analytics.framework/Headers"
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_LDFLAGS = $(inherited) -framework "Analytics" -framework "Security"
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
9 | PODS_ROOT = ${SRCROOT}/Pods
10 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Pods-AnalyticsSwiftExample/Pods-AnalyticsSwiftExample.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_AnalyticsSwiftExample {
2 | umbrella header "Pods-AnalyticsSwiftExample-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/AnalyticsSwiftExample/Pods/Target Support Files/Pods-AnalyticsSwiftExample/Pods-AnalyticsSwiftExample.release.xcconfig:
--------------------------------------------------------------------------------
1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Analytics"
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Analytics/Analytics.framework/Headers"
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_LDFLAGS = $(inherited) -framework "Analytics" -framework "Security"
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
9 | PODS_ROOT = ${SRCROOT}/Pods
10 |
--------------------------------------------------------------------------------
/AnalyticsSwiftTests/AnalyticsSwiftTests.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright © 2015 Segment, Inc.
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Cocoa
24 | import XCTest
25 | import AnalyticsSwift
26 |
27 | final class AnalyticsSwiftTests: XCTestCase {
28 | func testExample() {
29 | let analytics = Analytics(writeKey: "Z2qQi0HsunlFVULJmUi6R0JAwIF2S7R1", queue: Array(),
30 | executor: SynchronousExecutor(name: "com.segment.executor.test"))
31 | for index in 1...21 {
32 | analytics.enqueue(messageBuilder: TrackMessageBuilder(event: "hello, world" + String(index)).userId("prateek"))
33 | analytics.enqueue(messageBuilder: TrackMessageBuilder(event: "bye, world" + String(index)).userId("prateek"))
34 | }
35 | print("Sent messages to client.")
36 | analytics.flush()
37 | print("Triggered explicit flush.")
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/AnalyticsSwiftTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/AnalyticsSwiftTests/SynchronousExecutor.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright © 2015 Segment, Inc.
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import Foundation
24 | import AnalyticsSwift
25 |
26 | /** An Executor implementation that runs tasks and blocks until they complete. */
27 |
28 | public class SynchronousExecutor: Executor {
29 | private let dispatcher: DispatchQueue
30 |
31 | init(name: String) {
32 | self.dispatcher = DispatchQueue(label: name)
33 | }
34 |
35 | public func submit(task: @escaping () -> ()) {
36 | dispatcher.sync(execute: task)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Segment, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # Targets.
3 | #
4 |
5 | clean:
6 | @xcodebuild clean
7 |
8 | test:
9 | @xctool -scheme AnalyticsSwift test
10 |
11 | build:
12 | @xcodebuild
13 |
14 | #
15 | # Phonies.
16 | #
17 |
18 | .PHONY: clean
19 | .PHONY: test
20 | .PHONY: build
21 |
22 |
--------------------------------------------------------------------------------