diff --git a/.circleci/config.yml b/.circleci/config.yml index b924bd315..fec820d77 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,5 +1,4 @@ -version: 2 - +version: 2.1 jobs: build_and_test: macos: diff --git a/Analytics.xcodeproj/project.pbxproj b/Analytics.xcodeproj/project.pbxproj index 30c717803..890bf48f4 100644 --- a/Analytics.xcodeproj/project.pbxproj +++ b/Analytics.xcodeproj/project.pbxproj @@ -12,6 +12,8 @@ 630FC8EA2107F2A500A759C5 /* SEGScreenReporting.h in Headers */ = {isa = PBXBuildFile; fileRef = 5AF0EDFEDC0EE79A0A0EB713 /* SEGScreenReporting.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6E265C791FB1178C0030E08E /* IntegrationsManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E265C781FB1178C0030E08E /* IntegrationsManagerTest.swift */; }; 6EEC1C712017EA370089C478 /* EndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EEC1C702017EA370089C478 /* EndToEndTests.swift */; }; + 96A12C2824B680DB00949804 /* NSViewController+SEGScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 96A12C2624B680DB00949804 /* NSViewController+SEGScreen.h */; }; + 96A12C2924B680DB00949804 /* NSViewController+SEGScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A12C2724B680DB00949804 /* NSViewController+SEGScreen.m */; }; 9D8CE59023EE014E00197D0C /* CryptoTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADEB8E91DECD335005322DA /* CryptoTest.swift */; }; 9D8CE59123EE014E00197D0C /* UserDefaultsStorageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADEB8E61DECD335005322DA /* UserDefaultsStorageTest.swift */; }; 9D8CE59223EE014E00197D0C /* TrackingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA542761EB4035400945DA7 /* TrackingTests.swift */; }; @@ -130,6 +132,8 @@ 66058A0DB75544E7C2766C31 /* Pods_AnalyticsTestsTVOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AnalyticsTestsTVOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6E265C781FB1178C0030E08E /* IntegrationsManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationsManagerTest.swift; sourceTree = ""; }; 6EEC1C702017EA370089C478 /* EndToEndTests.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = EndToEndTests.swift; sourceTree = ""; tabWidth = 4; }; + 96A12C2624B680DB00949804 /* NSViewController+SEGScreen.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSViewController+SEGScreen.h"; sourceTree = ""; }; + 96A12C2724B680DB00949804 /* NSViewController+SEGScreen.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSViewController+SEGScreen.m"; sourceTree = ""; }; 9D8CE5A723EE014E00197D0C /* AnalyticsTestsTVOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AnalyticsTestsTVOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; A31958EE2385AC3A00A47EFA /* SerializationTests.m */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = SerializationTests.m; sourceTree = ""; tabWidth = 4; }; A34CC6DB249AAEBA00C5E368 /* SEGState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SEGState.m; sourceTree = ""; }; @@ -390,6 +394,8 @@ EADEB8A11DECD12B005322DA /* SEGUtils.m */, EADEB8A21DECD12B005322DA /* UIViewController+SEGScreen.h */, EADEB8A31DECD12B005322DA /* UIViewController+SEGScreen.m */, + 96A12C2624B680DB00949804 /* NSViewController+SEGScreen.h */, + 96A12C2724B680DB00949804 /* NSViewController+SEGScreen.m */, ); path = Internal; sourceTree = ""; @@ -423,6 +429,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 96A12C2824B680DB00949804 /* NSViewController+SEGScreen.h in Headers */, A34CC6DE249AAEBB00C5E368 /* SEGState.h in Headers */, EADEB8DC1DECD12B005322DA /* SEGAnalytics.h in Headers */, EADEB8B81DECD12B005322DA /* SEGIntegrationFactory.h in Headers */, @@ -534,7 +541,7 @@ }; EADEB85A1DECD080005322DA = { CreatedOnToolsVersion = 8.1; - ProvisioningStyle = Automatic; + ProvisioningStyle = Manual; }; EADEB8691DECD0EF005322DA = { CreatedOnToolsVersion = 8.1; @@ -703,6 +710,7 @@ EADEB8BE1DECD12B005322DA /* SEGScreenPayload.m in Sources */, EADEB8B61DECD12B005322DA /* SEGIdentifyPayload.m in Sources */, EADEB8CE1DECD12B005322DA /* SEGSegmentIntegrationFactory.m in Sources */, + 96A12C2924B680DB00949804 /* NSViewController+SEGScreen.m in Sources */, EADEB8C01DECD12B005322DA /* SEGTrackPayload.m in Sources */, EADEB8AF1DECD12B005322DA /* SEGAES256Crypto.m in Sources */, EADEB8C81DECD12B005322DA /* SEGHTTPClient.m in Sources */, @@ -922,7 +930,9 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -931,9 +941,11 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.segment.Analytics; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvos appletvsimulator"; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvos appletvsimulator macosx"; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; }; @@ -945,7 +957,9 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -954,9 +968,11 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.segment.Analytics; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvos appletvsimulator"; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvos appletvsimulator macosx"; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; }; diff --git a/Analytics/Classes/Analytics.h b/Analytics/Classes/Analytics.h index 458d55500..e52aad85a 100644 --- a/Analytics/Classes/Analytics.h +++ b/Analytics/Classes/Analytics.h @@ -6,7 +6,7 @@ // Copyright © 2016 Segment. All rights reserved. // -#import +#import //! Project version number for Analytics. FOUNDATION_EXPORT double AnalyticsVersionNumber; diff --git a/Analytics/Classes/SEGAnalytics.m b/Analytics/Classes/SEGAnalytics.m index 725675a98..db1ec7a7d 100644 --- a/Analytics/Classes/SEGAnalytics.m +++ b/Analytics/Classes/SEGAnalytics.m @@ -1,11 +1,11 @@ #import -#import #import "SEGAnalyticsUtils.h" #import "SEGAnalytics.h" #import "SEGIntegrationFactory.h" #import "SEGIntegration.h" #import "SEGSegmentIntegrationFactory.h" #import "UIViewController+SEGScreen.h" +#import "NSViewController+SEGScreen.h" #import "SEGStoreKitTracker.h" #import "SEGHTTPClient.h" #import "SEGStorage.h" @@ -56,12 +56,12 @@ - (instancetype)initWithConfiguration:(SEGAnalyticsConfiguration *)configuration self.runner = [[SEGMiddlewareRunner alloc] initWithMiddleware: [configuration.sourceMiddleware ?: @[] arrayByAddingObject:self.integrationsManager]]; - // Attach to application state change hooks - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - // Pass through for application state change events id application = configuration.application; if (application) { +#if TARGET_OS_IPHONE + // Attach to application state change hooks + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; for (NSString *name in @[ UIApplicationDidEnterBackgroundNotification, UIApplicationDidFinishLaunchingNotification, UIApplicationWillEnterForegroundNotification, @@ -70,18 +70,40 @@ - (instancetype)initWithConfiguration:(SEGAnalyticsConfiguration *)configuration UIApplicationDidBecomeActiveNotification ]) { [nc addObserver:self selector:@selector(handleAppStateNotification:) name:name object:application]; } +#elif TARGET_OS_OSX + // Attach to application state change hooks + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + for (NSString *name in @[ NSApplicationWillUnhideNotification, + NSApplicationDidFinishLaunchingNotification, + NSApplicationWillResignActiveNotification, + NSApplicationDidHideNotification, + NSApplicationDidBecomeActiveNotification, + NSApplicationWillTerminateNotification]) { + [nc addObserver:self selector:@selector(handleAppStateNotification:) name:name object:application]; + } +#endif } +#if TARGET_OS_IPHONE if (configuration.recordScreenViews) { [UIViewController seg_swizzleViewDidAppear]; } +#elif TARGET_OS_OSX + if (configuration.recordScreenViews) { + [NSViewController seg_swizzleViewDidAppear]; + } +#endif if (configuration.trackInAppPurchases) { _storeKitTracker = [SEGStoreKitTracker trackTransactionsForAnalytics:self]; } #if !TARGET_OS_TV if (configuration.trackPushNotifications && configuration.launchOptions) { +#if TARGET_OS_IOS NSDictionary *remoteNotification = configuration.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; +#else + NSDictionary *remoteNotification = configuration.launchOptions[NSApplicationLaunchUserNotificationKey]; +#endif if (remoteNotification) { [self trackPushNotification:remoteNotification fromLaunch:YES]; } @@ -105,6 +127,7 @@ - (void)dealloc NSString *const SEGBuildKeyV1 = @"SEGBuildKey"; NSString *const SEGBuildKeyV2 = @"SEGBuildKeyV2"; +#if TARGET_OS_IPHONE - (void)handleAppStateNotification:(NSNotification *)note { SEGApplicationLifecyclePayload *payload = [[SEGApplicationLifecyclePayload alloc] init]; @@ -119,6 +142,22 @@ - (void)handleAppStateNotification:(NSNotification *)note [self _applicationDidEnterBackground]; } } +#elif TARGET_OS_OSX +- (void)handleAppStateNotification:(NSNotification *)note +{ + SEGApplicationLifecyclePayload *payload = [[SEGApplicationLifecyclePayload alloc] init]; + payload.notificationName = note.name; + [self run:SEGEventTypeApplicationLifecycle payload:payload]; + + if ([note.name isEqualToString:NSApplicationDidFinishLaunchingNotification]) { + [self _applicationDidFinishLaunchingWithOptions:note.userInfo]; + } else if ([note.name isEqualToString:NSApplicationWillUnhideNotification]) { + [self _applicationWillEnterForeground]; + } else if ([note.name isEqualToString: NSApplicationDidHideNotification]) { + [self _applicationDidEnterBackground]; + } +} +#endif - (void)_applicationDidFinishLaunchingWithOptions:(NSDictionary *)launchOptions { @@ -153,6 +192,7 @@ - (void)_applicationDidFinishLaunchingWithOptions:(NSDictionary *)launchOptions }]; } +#if TARGET_OS_IPHONE [self track:@"Application Opened" properties:@{ @"from_background" : @NO, @"version" : currentVersion ?: @"", @@ -160,6 +200,14 @@ - (void)_applicationDidFinishLaunchingWithOptions:(NSDictionary *)launchOptions @"referring_application" : launchOptions[UIApplicationLaunchOptionsSourceApplicationKey] ?: @"", @"url" : launchOptions[UIApplicationLaunchOptionsURLKey] ?: @"", }]; +#elif TARGET_OS_OSX + [self track:@"Application Opened" properties:@{ + @"from_background" : @NO, + @"version" : currentVersion ?: @"", + @"build" : currentBuild ?: @"", + @"default_launch" : launchOptions[NSApplicationLaunchIsDefaultLaunchKey] ?: @(YES), + }]; +#endif [[NSUserDefaults standardUserDefaults] setObject:currentVersion forKey:SEGVersionKey]; diff --git a/Analytics/Classes/SEGAnalyticsConfiguration.h b/Analytics/Classes/SEGAnalyticsConfiguration.h index 5177f93ac..b8e18c2bc 100644 --- a/Analytics/Classes/SEGAnalyticsConfiguration.h +++ b/Analytics/Classes/SEGAnalyticsConfiguration.h @@ -7,18 +7,33 @@ // #import + +#if TARGET_OS_IPHONE #import +#elif TARGET_OS_OSX +#import +#endif NS_SWIFT_NAME(ApplicationProtocol) @protocol SEGApplicationProtocol + +#if TARGET_OS_IPHONE @property (nullable, nonatomic, assign) id delegate; - (NSUInteger)seg_beginBackgroundTaskWithName:(nullable NSString *)taskName expirationHandler:(void (^__nullable)(void))handler; - (void)seg_endBackgroundTask:(NSUInteger)identifier; +#elif TARGET_OS_OSX +@property (nullable, nonatomic, assign) id delegate; +#endif @end - +#if TARGET_OS_IOS @interface UIApplication (SEGApplicationProtocol) @end +#elif TARGET_OS_OSX +@interface NSApplication (SEGApplicationProtocol) +@end +#endif + typedef NSMutableURLRequest *_Nonnull (^SEGRequestFactory)(NSURL *_Nonnull); typedef NSString *_Nonnull (^SEGAdSupportBlock)(void); diff --git a/Analytics/Classes/SEGAnalyticsConfiguration.m b/Analytics/Classes/SEGAnalyticsConfiguration.m index fdf04a3fe..cd7fe0d60 100644 --- a/Analytics/Classes/SEGAnalyticsConfiguration.m +++ b/Analytics/Classes/SEGAnalyticsConfiguration.m @@ -9,9 +9,13 @@ #import "SEGAnalyticsConfiguration.h" #import "SEGAnalytics.h" #import "SEGCrypto.h" +#if TARGET_OS_IPHONE #import +#elif TARGET_OS_OSX +#import +#endif - +#if TARGET_OS_IPHONE @implementation UIApplication (SEGApplicationProtocol) - (UIBackgroundTaskIdentifier)seg_beginBackgroundTaskWithName:(nullable NSString *)taskName expirationHandler:(void (^__nullable)(void))handler @@ -25,6 +29,7 @@ - (void)seg_endBackgroundTask:(UIBackgroundTaskIdentifier)identifier } @end +#endif @implementation SEGAnalyticsExperimental @end @@ -67,9 +72,15 @@ - (instancetype)init @"(fb\\d+://authorize#access_token=)([^ ]+)": @"$1((redacted/fb-auth-token))" }; _factories = [NSMutableArray array]; +#if TARGET_OS_IPHONE if ([UIApplication respondsToSelector:@selector(sharedApplication)]) { _application = [UIApplication performSelector:@selector(sharedApplication)]; } +#elif TARGET_OS_OSX + if ([NSApplication respondsToSelector:@selector(sharedApplication)]) { + _application = [NSApplication performSelector:@selector(sharedApplication)]; + } +#endif } return self; } diff --git a/Analytics/Classes/SEGScreenReporting.h b/Analytics/Classes/SEGScreenReporting.h index f40a05887..1cce6c7dc 100644 --- a/Analytics/Classes/SEGScreenReporting.h +++ b/Analytics/Classes/SEGScreenReporting.h @@ -1,4 +1,9 @@ +#if TARGET_OS_IPHONE #import +#elif TARGET_OS_OSX +#import +#endif + #import "SEGSerializableValue.h" /** Implement this protocol to override automatic screen reporting @@ -8,8 +13,13 @@ NS_ASSUME_NONNULL_BEGIN @protocol SEGScreenReporting @optional --(void) seg_trackScreen:(UIViewController*)screen name:(NSString*)name; +#if TARGET_OS_IPHONE +- (void)seg_trackScreen:(UIViewController*)screen name:(NSString*)name; @property (readonly, nullable) UIViewController *seg_mainViewController; +#elif TARGET_OS_OSX +- (void)seg_trackScreen:(NSViewController*)screen name:(NSString*)name; +@property (readonly, nullable) NSViewController *seg_mainViewController; +#endif @end NS_ASSUME_NONNULL_END diff --git a/Analytics/Classes/SEGSegmentIntegration.m b/Analytics/Classes/SEGSegmentIntegration.m index 1687a79c1..e4e5a7bcd 100644 --- a/Analytics/Classes/SEGSegmentIntegration.m +++ b/Analytics/Classes/SEGSegmentIntegration.m @@ -1,6 +1,5 @@ #include -#import #import "SEGAnalytics.h" #import "SEGUtils.h" #import "SEGSegmentIntegration.h" @@ -10,6 +9,10 @@ #import "SEGMacros.h" #import "SEGState.h" +#if TARGET_OS_IPHONE +#import +#endif + #if TARGET_OS_IOS #import #import @@ -31,7 +34,6 @@ @interface SEGSegmentIntegration () @property (nonatomic, strong) NSMutableArray *queue; @property (nonatomic, strong) NSURLSessionUploadTask *batchRequest; -@property (nonatomic, assign) UIBackgroundTaskIdentifier flushTaskID; @property (nonatomic, strong) SEGReachability *reachability; @property (nonatomic, strong) NSTimer *flushTimer; @property (nonatomic, strong) dispatch_queue_t serialQueue; @@ -47,6 +49,10 @@ @interface SEGSegmentIntegration () @property (nonatomic, strong) id userDefaultsStorage; @property (nonatomic, strong) NSURLSessionDataTask *attributionRequest; +#if TARGET_OS_IPHONE +@property (nonatomic, assign) UIBackgroundTaskIdentifier flushTaskID; +#endif + @end @@ -66,7 +72,9 @@ - (id)initWithAnalytics:(SEGAnalytics *)analytics httpClient:(SEGHTTPClient *)ht [self.reachability startNotifier]; self.serialQueue = seg_dispatch_queue_create_specific("io.segment.analytics.segmentio", DISPATCH_QUEUE_SERIAL); self.backgroundTaskQueue = seg_dispatch_queue_create_specific("io.segment.analytics.backgroundTask", DISPATCH_QUEUE_SERIAL); +#if TARGET_OS_IPHONE self.flushTaskID = UIBackgroundTaskInvalid; +#endif // load traits & user from disk. [self loadUserId]; @@ -110,6 +118,7 @@ - (void)dispatchBackgroundAndWait:(void (^)(void))block seg_dispatch_specific_sync(_serialQueue, block); } +#if TARGET_OS_IPHONE - (void)beginBackgroundTask { [self endBackgroundTask]; @@ -144,6 +153,7 @@ - (void)endBackgroundTask } }); } +#endif - (NSString *)description { @@ -316,6 +326,17 @@ - (void)flush - (void)flushWithMaxSize:(NSUInteger)maxBatchSize { + void (^startBatch)(void) = ^{ + NSArray *batch; + if ([self.queue count] >= maxBatchSize) { + batch = [self.queue subarrayWithRange:NSMakeRange(0, maxBatchSize)]; + } else { + batch = [NSArray arrayWithArray:self.queue]; + } + [self sendData:batch]; + }; + +#if TARGET_OS_IPHONE [self dispatchBackground:^{ if ([self.queue count] == 0) { SEGLog(@"%@ No queued API calls to flush.", self); @@ -326,16 +347,12 @@ - (void)flushWithMaxSize:(NSUInteger)maxBatchSize SEGLog(@"%@ API request already in progress, not flushing again.", self); return; } - - NSArray *batch; - if ([self.queue count] >= maxBatchSize) { - batch = [self.queue subarrayWithRange:NSMakeRange(0, maxBatchSize)]; - } else { - batch = [NSArray arrayWithArray:self.queue]; - } - - [self sendData:batch]; + // here + startBatch(); }]; +#elif TARGET_OS_OSX + startBatch(); +#endif } - (void)flushQueueByLength @@ -382,7 +399,9 @@ - (void)sendData:(NSArray *)batch SEGLog(@"Flushing batch %@.", payload); self.batchRequest = [self.httpClient upload:payload forWriteKey:self.configuration.writeKey completionHandler:^(BOOL retry) { - [self dispatchBackground:^{ + +#if TARGET_OS_IPHONE + void (^completion)(void) = ^{ if (retry) { [self notifyForName:SEGSegmentRequestDidFailNotification userInfo:batch]; self.batchRequest = nil; @@ -395,12 +414,29 @@ - (void)sendData:(NSArray *)batch [self notifyForName:SEGSegmentRequestDidSucceedNotification userInfo:batch]; self.batchRequest = nil; [self endBackgroundTask]; - }]; + }; +#elif TARGET_OS_OSX + void (^completion)(void) = ^{ + if (retry) { + [self notifyForName:SEGSegmentRequestDidFailNotification userInfo:batch]; + self.batchRequest = nil; + return; + } + + [self.queue removeObjectsInArray:batch]; + [self persistQueue]; + [self notifyForName:SEGSegmentRequestDidSucceedNotification userInfo:batch]; + self.batchRequest = nil; + }; +#endif + + [self dispatchBackground:completion]; }]; [self notifyForName:SEGSegmentDidSendRequestNotification userInfo:batch]; } +#if TARGET_OS_IPHONE - (void)applicationDidEnterBackground { [self beginBackgroundTask]; @@ -408,6 +444,7 @@ - (void)applicationDidEnterBackground // since there is a chance that the user will never launch the app again. [self flush]; } +#endif - (void)applicationWillTerminate { diff --git a/Analytics/Internal/NSViewController+SEGScreen.h b/Analytics/Internal/NSViewController+SEGScreen.h new file mode 100644 index 000000000..6e4b54bff --- /dev/null +++ b/Analytics/Internal/NSViewController+SEGScreen.h @@ -0,0 +1,21 @@ +// +// NSViewController+SEGScreen.h +// Analytics +// +// Created by Cody Garvin on 7/8/20. +// Copyright © 2020 Segment. All rights reserved. +// + +#import "SEGSerializableValue.h" + +#if TARGET_OS_OSX +#import + +@interface NSViewController (SEGScreen) + ++ (void)seg_swizzleViewDidAppear; ++ (NSViewController *)seg_rootViewControllerFromView:(NSView *)view; + +@end + +#endif diff --git a/Analytics/Internal/NSViewController+SEGScreen.m b/Analytics/Internal/NSViewController+SEGScreen.m new file mode 100644 index 000000000..4558496d5 --- /dev/null +++ b/Analytics/Internal/NSViewController+SEGScreen.m @@ -0,0 +1,99 @@ +// +// NSViewController+SEGScreen.m +// Analytics +// +// Created by Cody Garvin on 7/8/20. +// Copyright © 2020 Segment. All rights reserved. +// + +#import "NSViewController+SEGScreen.h" +#import +#import "SEGAnalytics.h" +#import "SEGAnalyticsUtils.h" +#import "SEGScreenReporting.h" + + +#if TARGET_OS_OSX +@implementation NSViewController (SEGScreen) + ++ (void)seg_swizzleViewDidAppear +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class class = [self class]; + + SEL originalSelector = @selector(viewDidAppear:); + SEL swizzledSelector = @selector(seg_viewDidAppear:); + + Method originalMethod = class_getInstanceMethod(class, originalSelector); + Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); + + BOOL didAddMethod = + class_addMethod(class, + originalSelector, + method_getImplementation(swizzledMethod), + method_getTypeEncoding(swizzledMethod)); + + if (didAddMethod) { + class_replaceMethod(class, + swizzledSelector, + method_getImplementation(originalMethod), + method_getTypeEncoding(originalMethod)); + } else { + method_exchangeImplementations(originalMethod, swizzledMethod); + } + }); +} + ++ (NSViewController *)seg_rootViewControllerFromView:(NSView *)view +{ + NSViewController *rootViewController = view.window.contentViewController; + + if (rootViewController.childViewControllers.count > 0) { + if ([rootViewController conformsToProtocol:@protocol(SEGScreenReporting)] && [rootViewController respondsToSelector:@selector(seg_mainViewController)]) { + __auto_type screenReporting = (NSViewController*)rootViewController; + return screenReporting.seg_mainViewController; + } + + // fall back on first child UIViewController as a "best guess" assumption + __auto_type *firstChildViewController = rootViewController.childViewControllers.firstObject; + if (firstChildViewController != nil) { + return firstChildViewController; + } + } + + return rootViewController; +} + +- (void)seg_viewDidAppear:(BOOL)animated +{ + NSViewController *top = [[self class] seg_rootViewControllerFromView:self.view]; + if (!top) { + SEGLog(@"Could not infer screen."); + return; + } + + NSString *name = [[[top class] description] stringByReplacingOccurrencesOfString:@"ViewController" withString:@""]; + + if (!name || name.length == 0) { + // if no class description found, try view controller's title. + name = [top title]; + // Class name could be just "ViewController". + if (name.length == 0) { + SEGLog(@"Could not infer screen name."); + name = @"Unknown"; + } + } + + if ([top conformsToProtocol:@protocol(SEGScreenReporting)] && [top respondsToSelector:@selector(seg_trackScreen:name:)]) { + __auto_type screenReporting = (NSViewController*)top; + [screenReporting seg_trackScreen:top name:name]; + return; + } + + [[SEGAnalytics sharedAnalytics] screen:name properties:nil options:nil]; + + [self seg_viewDidAppear:animated]; +} +@end +#endif diff --git a/Analytics/Internal/SEGIntegrationsManager.m b/Analytics/Internal/SEGIntegrationsManager.m index 6fa67be96..8d327b915 100644 --- a/Analytics/Internal/SEGIntegrationsManager.m +++ b/Analytics/Internal/SEGIntegrationsManager.m @@ -6,7 +6,9 @@ // Copyright © 2016 Segment. All rights reserved. // +#if TARGET_OS_IPHONE #import +#endif #import #import "SEGAnalyticsUtils.h" #import "SEGAnalytics.h" @@ -114,13 +116,16 @@ - (instancetype _Nonnull)initWithAnalytics:(SEGAnalytics *_Nonnull)analytics // Update settings on each integration immediately [self refreshSettings]; - // Attach to application state change hooks - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - // Update settings on foreground id application = configuration.application; if (application) { + // Attach to application state change hooks + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; +#if TARGET_OS_IPHONE [nc addObserver:self selector:@selector(onAppForeground:) name:UIApplicationWillEnterForegroundNotification object:application]; +#elif TARGET_OS_OSX + [nc addObserver:self selector:@selector(onAppForeground:) name:NSApplicationWillUnhideNotification object:application]; +#endif } } return self; @@ -148,13 +153,14 @@ - (void)onAppForeground:(NSNotification *)note [self refreshSettings]; } - - (void)handleAppStateNotification:(NSString *)notificationName { SEGLog(@"Application state change notification: %@", notificationName); static NSDictionary *selectorMapping; static dispatch_once_t selectorMappingOnce; dispatch_once(&selectorMappingOnce, ^{ +#if TARGET_OS_IPHONE + selectorMapping = @{ UIApplicationDidFinishLaunchingNotification : NSStringFromSelector(@selector(applicationDidFinishLaunching:)), @@ -169,6 +175,23 @@ - (void)handleAppStateNotification:(NSString *)notificationName UIApplicationDidBecomeActiveNotification : NSStringFromSelector(@selector(applicationDidBecomeActive)) }; +#elif TARGET_OS_OSX + selectorMapping = @{ + NSApplicationDidFinishLaunchingNotification : + NSStringFromSelector(@selector(applicationDidFinishLaunching:)), + NSApplicationDidHideNotification : + NSStringFromSelector(@selector(applicationDidEnterBackground)), + NSApplicationWillUnhideNotification : + NSStringFromSelector(@selector(applicationWillEnterForeground)), + NSApplicationWillTerminateNotification : + NSStringFromSelector(@selector(applicationWillTerminate)), + NSApplicationWillResignActiveNotification : + NSStringFromSelector(@selector(applicationWillResignActive)), + NSApplicationDidBecomeActiveNotification : + NSStringFromSelector(@selector(applicationDidBecomeActive)) + }; +#endif + }); SEL selector = NSSelectorFromString(selectorMapping[notificationName]); if (selector) { @@ -176,7 +199,6 @@ - (void)handleAppStateNotification:(NSString *)notificationName } } - #pragma mark - Public API - (NSString *)description @@ -705,10 +727,6 @@ - (void)context:(SEGContext *)context next:(void (^_Nonnull)(SEGContext *_Nullab forRemoteNotification:payload.userInfo]; break; } - case SEGEventTypeApplicationLifecycle: - [self handleAppStateNotification: - [(SEGApplicationLifecyclePayload *)context.payload notificationName]]; - break; case SEGEventTypeContinueUserActivity: [self continueUserActivity: [(SEGContinueUserActivityPayload *)context.payload activity]]; @@ -718,6 +736,11 @@ - (void)context:(SEGContext *)context next:(void (^_Nonnull)(SEGContext *_Nullab [self openURL:payload.url options:payload.options]; break; } + case SEGEventTypeApplicationLifecycle: + [self handleAppStateNotification: + [(SEGApplicationLifecyclePayload *)context.payload notificationName]]; + break; + default: case SEGEventTypeUndefined: NSAssert(NO, @"Received context with undefined event type %@", context); SEGLog(@"[ERROR]: Received context with undefined event type %@", context); diff --git a/Analytics/Internal/SEGMacros.h b/Analytics/Internal/SEGMacros.h index bfc470046..f07ad6b7f 100644 --- a/Analytics/Internal/SEGMacros.h +++ b/Analytics/Internal/SEGMacros.h @@ -9,6 +9,8 @@ #ifndef SEGMacros_h #define SEGMacros_h +#import "TargetConditionals.h" + #define __deprecated__(s) __attribute__((deprecated(s))) #define weakify(var) __weak typeof(var) __weak_##var = var; @@ -19,4 +21,8 @@ _Pragma("clang diagnostic ignored \"-Wshadow\"") \ __strong typeof(var) var = __weak_##var; \ _Pragma("clang diagnostic pop") +#if TARGET_OS_IOS == 1 || TARGET_OS_TV == 1 +#define TARGET_UIKIT 1 +#endif + #endif /* SEGMacros_h */ diff --git a/Analytics/Internal/SEGUtils.h b/Analytics/Internal/SEGUtils.h index be350685a..1d7e8b85c 100644 --- a/Analytics/Internal/SEGUtils.h +++ b/Analytics/Internal/SEGUtils.h @@ -32,6 +32,12 @@ NSDictionary *getLiveContext(SEGReachability *reachability, NSDictionary * _Null NSString *GenerateUUIDString(void); +#if TARGET_OS_IPHONE +NSDictionary *mobileSpecifications(SEGAnalyticsConfiguration *configuration, NSString * _Nullable deviceToken); +#elif TARGET_OS_OSX +NSDictionary *desktopSpecifications(SEGAnalyticsConfiguration *configuration, NSString * _Nullable deviceToken); +#endif + // Date Utils NSString *iso8601FormattedString(NSDate *date); NSString *iso8601NanoFormattedString(NSDate *date); diff --git a/Analytics/Internal/SEGUtils.m b/Analytics/Internal/SEGUtils.m index 5a4ce926c..ccd01fd8e 100644 --- a/Analytics/Internal/SEGUtils.m +++ b/Analytics/Internal/SEGUtils.m @@ -10,9 +10,13 @@ #include -#if TARGET_OS_IOS +#if TARGET_OS_IOS && TARGET_OS_MACCATALYST == 0 #import #import + +static CTTelephonyNetworkInfo *_telephonyNetworkInfo; +#elif TARGET_OS_OSX +#import #endif // BKS: This doesn't appear to be needed anymore. Will investigate. @@ -167,15 +171,32 @@ BOOL getAdTrackingEnabled(SEGAnalyticsConfiguration *configuration) }; } - UIDevice *device = [UIDevice currentDevice]; +#if TARGET_OS_IPHONE + dict[@"device"] = mobileSpecifications(configuration, deviceToken); +#elif TARGET_OS_OSX + dict[@"device"] = desktopSpecifications(configuration, deviceToken); +#endif + + return dict; +} +#if TARGET_OS_IPHONE +NSDictionary *mobileSpecifications(SEGAnalyticsConfiguration *configuration, NSString *deviceToken) +{ + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + UIDevice *device = [UIDevice currentDevice]; dict[@"device"] = ({ NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; dict[@"manufacturer"] = @"Apple"; +#if TARGET_OS_MACCATALYST + dict[@"type"] = @"macos"; + dict[@"name"] = @"Macintosh"; +#else dict[@"type"] = @"ios"; + dict[@"name"] = [device model]; +#endif dict[@"model"] = getDeviceModel(); dict[@"id"] = [[device identifierForVendor] UUIDString]; - dict[@"name"] = [device model]; if (getAdTrackingEnabled(configuration)) { NSString *idfa = configuration.adSupportBlock(); // This isn't ideal. We're doing this because we can't actually check if IDFA is enabled on @@ -203,33 +224,91 @@ BOOL getAdTrackingEnabled(SEGAnalyticsConfiguration *configuration) @"width" : @(screenSize.width), @"height" : @(screenSize.height) }; + + // BKS: This bit below doesn't seem to be effective anymore. Will investigate later. + /*#if !(TARGET_IPHONE_SIMULATOR) + Class adClient = NSClassFromString(SEGADClientClass); + if (adClient) { + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Warc-performSelector-leaks" + id sharedClient = [adClient performSelector:NSSelectorFromString(@"sharedClient")]; + #pragma clang diagnostic pop + void (^completionHandler)(BOOL iad) = ^(BOOL iad) { + if (iad) { + dict[@"referrer"] = @{ @"type" : @"iad" }; + } + }; + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Warc-performSelector-leaks" + [sharedClient performSelector:NSSelectorFromString(@"determineAppInstallationAttributionWithCompletionHandler:") + withObject:completionHandler]; + #pragma clang diagnostic pop + } + #endif*/ + + return dict; +} +#endif + +#if TARGET_OS_OSX +NSString *getMacUUID() +{ + char buf[512] = { 0 }; + int bufSize = sizeof(buf); + io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/"); + CFStringRef uuidCf = (CFStringRef) IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); + IOObjectRelease(ioRegistryRoot); + CFStringGetCString(uuidCf, buf, bufSize, kCFStringEncodingMacRoman); + CFRelease(uuidCf); + return [NSString stringWithUTF8String:buf]; +} + +NSDictionary *desktopSpecifications(SEGAnalyticsConfiguration *configuration, NSString *deviceToken) +{ + NSProcessInfo *deviceInfo = [NSProcessInfo processInfo]; + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + dict[@"device"] = ({ + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + dict[@"manufacturer"] = @"Apple"; + dict[@"type"] = @"macos"; + dict[@"model"] = getDeviceModel(); + dict[@"id"] = getMacUUID(); + dict[@"name"] = [deviceInfo hostName]; + + if (getAdTrackingEnabled(configuration)) { + NSString *idfa = configuration.adSupportBlock(); + // This isn't ideal. We're doing this because we can't actually check if IDFA is enabled on + // the customer device. Apple docs and tests show that if it is disabled, one gets back all 0's. + BOOL adTrackingEnabled = (![idfa isEqualToString:@"00000000-0000-0000-0000-000000000000"]); + dict[@"adTrackingEnabled"] = @(adTrackingEnabled); -// BKS: This bit below doesn't seem to be effective anymore. Will investigate later. -/*#if !(TARGET_IPHONE_SIMULATOR) - Class adClient = NSClassFromString(SEGADClientClass); - if (adClient) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - id sharedClient = [adClient performSelector:NSSelectorFromString(@"sharedClient")]; -#pragma clang diagnostic pop - void (^completionHandler)(BOOL iad) = ^(BOOL iad) { - if (iad) { - dict[@"referrer"] = @{ @"type" : @"iad" }; + if (adTrackingEnabled) { + dict[@"advertisingId"] = idfa; } - }; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - [sharedClient performSelector:NSSelectorFromString(@"determineAppInstallationAttributionWithCompletionHandler:") - withObject:completionHandler]; -#pragma clang diagnostic pop - } -#endif*/ + } + if (deviceToken && deviceToken.length > 0) { + dict[@"token"] = deviceToken; + } + dict; + }); + + dict[@"os"] = @{ + @"name" : deviceInfo.operatingSystemVersionString, + @"version" : [NSString stringWithFormat:@"%ld.%ld.%ld", + deviceInfo.operatingSystemVersion.majorVersion, + deviceInfo.operatingSystemVersion.minorVersion, + deviceInfo.operatingSystemVersion.patchVersion] + }; + + CGSize screenSize = [NSScreen mainScreen].frame.size; + dict[@"screen"] = @{ + @"width" : @(screenSize.width), + @"height" : @(screenSize.height) + }; return dict; } -#if TARGET_OS_IOS -static CTTelephonyNetworkInfo *_telephonyNetworkInfo; #endif NSDictionary *getLiveContext(SEGReachability *reachability, NSDictionary *referrer, NSDictionary *traits) @@ -250,7 +329,7 @@ BOOL getAdTrackingEnabled(SEGAnalyticsConfiguration *configuration) network[@"cellular"] = @(reachability.isReachableViaWWAN); } -#if TARGET_OS_IOS +#if TARGET_OS_IOS && TARGET_OS_MACCATALYST == 0 static dispatch_once_t networkInfoOnceToken; dispatch_once(&networkInfoOnceToken, ^{ _telephonyNetworkInfo = [[CTTelephonyNetworkInfo alloc] init]; diff --git a/Analytics/Internal/UIViewController+SEGScreen.h b/Analytics/Internal/UIViewController+SEGScreen.h index 0a22dabd2..8be5c8565 100644 --- a/Analytics/Internal/UIViewController+SEGScreen.h +++ b/Analytics/Internal/UIViewController+SEGScreen.h @@ -1,6 +1,8 @@ -#import #import "SEGSerializableValue.h" +#if TARGET_OS_IPHONE +#import + @interface UIViewController (SEGScreen) + (void)seg_swizzleViewDidAppear; @@ -8,3 +10,4 @@ @end +#endif diff --git a/Analytics/Internal/UIViewController+SEGScreen.m b/Analytics/Internal/UIViewController+SEGScreen.m index ecfb48aed..8fd35623a 100644 --- a/Analytics/Internal/UIViewController+SEGScreen.m +++ b/Analytics/Internal/UIViewController+SEGScreen.m @@ -5,6 +5,7 @@ #import "SEGScreenReporting.h" +#if TARGET_OS_IPHONE @implementation UIViewController (SEGScreen) + (void)seg_swizzleViewDidAppear @@ -120,3 +121,4 @@ - (void)seg_viewDidAppear:(BOOL)animated } @end +#endif diff --git a/Examples/CarthageExample/CarthageExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Examples/CarthageExample/CarthageExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Examples/CarthageExample/CarthageExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Examples/FullExampleFlow/Analytics Example.xcodeproj/project.pbxproj b/Examples/FullExampleFlow/Analytics Example.xcodeproj/project.pbxproj index dd841bcd2..269a8fc1f 100644 --- a/Examples/FullExampleFlow/Analytics Example.xcodeproj/project.pbxproj +++ b/Examples/FullExampleFlow/Analytics Example.xcodeproj/project.pbxproj @@ -9,10 +9,10 @@ /* Begin PBXBuildFile section */ 9616DB59249050A600F7191B /* SignupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9616DB58249050A600F7191B /* SignupViewController.swift */; }; 9616DB5B2490583800F7191B /* InviteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9616DB5A2490583800F7191B /* InviteViewController.swift */; }; + 961C617024BE5BED00A8B8E3 /* Analytics in Frameworks */ = {isa = PBXBuildFile; productRef = 961C616F24BE5BED00A8B8E3 /* Analytics */; }; 961D80C024902143007C4F04 /* AnonymousViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961D80BC24902143007C4F04 /* AnonymousViewController.swift */; }; 96BC0E4A24A57317000AF2EB /* SignoutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BC0E4924A57317000AF2EB /* SignoutViewController.swift */; }; 96BC0E4C24A693E3000AF2EB /* SignInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BC0E4B24A693E3000AF2EB /* SignInViewController.swift */; }; - 96BC0E4F24A6B342000AF2EB /* Analytics in Frameworks */ = {isa = PBXBuildFile; productRef = 96BC0E4E24A6B342000AF2EB /* Analytics */; }; 96BC0E5124AA72F6000AF2EB /* TrialEndViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BC0E5024AA72F6000AF2EB /* TrialEndViewController.swift */; }; 96D0441F2485B458009C3FD7 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96D0441E2485B458009C3FD7 /* AppDelegate.swift */; }; 96D044212485B458009C3FD7 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96D044202485B458009C3FD7 /* SceneDelegate.swift */; }; @@ -61,7 +61,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 96BC0E4F24A6B342000AF2EB /* Analytics in Frameworks */, + 961C617024BE5BED00A8B8E3 /* Analytics in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -140,7 +140,7 @@ ); name = "Analytics Example"; packageProductDependencies = ( - 96BC0E4E24A6B342000AF2EB /* Analytics */, + 961C616F24BE5BED00A8B8E3 /* Analytics */, ); productName = "Analytics Example"; productReference = 96D0441B2485B458009C3FD7 /* Analytics Example.app */; @@ -171,7 +171,7 @@ ); mainGroup = 96D044122485B458009C3FD7; packageReferences = ( - 96BC0E4D24A6B342000AF2EB /* XCRemoteSwiftPackageReference "analytics-ios" */, + 961C616E24BE5BED00A8B8E3 /* XCRemoteSwiftPackageReference "analytics-ios" */, ); productRefGroup = 96D0441C2485B458009C3FD7 /* Products */; projectDirPath = ""; @@ -354,8 +354,9 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 9EPD8ZWKX7; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", @@ -367,6 +368,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "com.Segment.Analytics-Example"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -376,8 +378,9 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 9EPD8ZWKX7; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", @@ -389,6 +392,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "com.Segment.Analytics-Example"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -418,20 +422,20 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 96BC0E4D24A6B342000AF2EB /* XCRemoteSwiftPackageReference "analytics-ios" */ = { + 961C616E24BE5BED00A8B8E3 /* XCRemoteSwiftPackageReference "analytics-ios" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "git@github.com:segmentio/analytics-ios.git"; + repositoryURL = "https://github.com/segmentio/analytics-ios.git"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.0.2; + branch = migs647/macconversion; + kind = branch; }; }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 96BC0E4E24A6B342000AF2EB /* Analytics */ = { + 961C616F24BE5BED00A8B8E3 /* Analytics */ = { isa = XCSwiftPackageProductDependency; - package = 96BC0E4D24A6B342000AF2EB /* XCRemoteSwiftPackageReference "analytics-ios" */; + package = 961C616E24BE5BED00A8B8E3 /* XCRemoteSwiftPackageReference "analytics-ios" */; productName = Analytics; }; /* End XCSwiftPackageProductDependency section */ diff --git a/Examples/FullExampleFlow/Analytics Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/FullExampleFlow/Analytics Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 000000000..5302431a3 --- /dev/null +++ b/Examples/FullExampleFlow/Analytics Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "Analytics", + "repositoryURL": "https://github.com/segmentio/analytics-ios.git", + "state": { + "branch": "migs647/macconversion", + "revision": "bd012c2c3fe26e228bdf386a7e38c0a6b4b761fc", + "version": null + } + } + ] + }, + "version": 1 +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example.xcodeproj/project.pbxproj b/Examples/FullExampleFlowCatalyst/Analytics Example.xcodeproj/project.pbxproj new file mode 100644 index 000000000..b754af4fe --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example.xcodeproj/project.pbxproj @@ -0,0 +1,454 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 9616DB59249050A600F7191B /* SignupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9616DB58249050A600F7191B /* SignupViewController.swift */; }; + 9616DB5B2490583800F7191B /* InviteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9616DB5A2490583800F7191B /* InviteViewController.swift */; }; + 961C616A24BE58FE00A8B8E3 /* Analytics in Frameworks */ = {isa = PBXBuildFile; productRef = 961C616924BE58FE00A8B8E3 /* Analytics */; }; + 961D80C024902143007C4F04 /* AnonymousViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961D80BC24902143007C4F04 /* AnonymousViewController.swift */; }; + 96BC0E4A24A57317000AF2EB /* SignoutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BC0E4924A57317000AF2EB /* SignoutViewController.swift */; }; + 96BC0E4C24A693E3000AF2EB /* SignInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BC0E4B24A693E3000AF2EB /* SignInViewController.swift */; }; + 96BC0E5124AA72F6000AF2EB /* TrialEndViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BC0E5024AA72F6000AF2EB /* TrialEndViewController.swift */; }; + 96D0441F2485B458009C3FD7 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96D0441E2485B458009C3FD7 /* AppDelegate.swift */; }; + 96D044212485B458009C3FD7 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96D044202485B458009C3FD7 /* SceneDelegate.swift */; }; + 96D044232485B458009C3FD7 /* StartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96D044222485B458009C3FD7 /* StartViewController.swift */; }; + 96D044262485B458009C3FD7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 96D044242485B458009C3FD7 /* Main.storyboard */; }; + 96D044282485B459009C3FD7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 96D044272485B459009C3FD7 /* Assets.xcassets */; }; + 96D0442B2485B459009C3FD7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 96D044292485B459009C3FD7 /* LaunchScreen.storyboard */; }; + 96EC569B2488567500B636AC /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96EC569A2488567500B636AC /* LoginViewController.swift */; }; + 96EC569D2488568D00B636AC /* StepsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96EC569C2488568D00B636AC /* StepsViewController.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 96D044422485B541009C3FD7 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 9616DB58249050A600F7191B /* SignupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignupViewController.swift; sourceTree = ""; }; + 9616DB5A2490583800F7191B /* InviteViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InviteViewController.swift; sourceTree = ""; }; + 961D80BC24902143007C4F04 /* AnonymousViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnonymousViewController.swift; sourceTree = ""; }; + 96A12BC024B6448900949804 /* Analytics Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Analytics Example.entitlements"; sourceTree = ""; }; + 96BC0E4924A57317000AF2EB /* SignoutViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignoutViewController.swift; sourceTree = ""; }; + 96BC0E4B24A693E3000AF2EB /* SignInViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignInViewController.swift; sourceTree = ""; }; + 96BC0E5024AA72F6000AF2EB /* TrialEndViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrialEndViewController.swift; sourceTree = ""; }; + 96D0441B2485B458009C3FD7 /* Analytics Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Analytics Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 96D0441E2485B458009C3FD7 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 96D044202485B458009C3FD7 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 96D044222485B458009C3FD7 /* StartViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartViewController.swift; sourceTree = ""; }; + 96D044252485B458009C3FD7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 96D044272485B459009C3FD7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 96D0442A2485B459009C3FD7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 96D0442C2485B459009C3FD7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 96EC569A2488567500B636AC /* LoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = ""; }; + 96EC569C2488568D00B636AC /* StepsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepsViewController.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 96D044182485B458009C3FD7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 961C616A24BE58FE00A8B8E3 /* Analytics in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 96D044122485B458009C3FD7 = { + isa = PBXGroup; + children = ( + 96D0441D2485B458009C3FD7 /* Analytics Example */, + 96D0441C2485B458009C3FD7 /* Products */, + 96D0443F2485B541009C3FD7 /* Frameworks */, + ); + sourceTree = ""; + }; + 96D0441C2485B458009C3FD7 /* Products */ = { + isa = PBXGroup; + children = ( + 96D0441B2485B458009C3FD7 /* Analytics Example.app */, + ); + name = Products; + sourceTree = ""; + }; + 96D0441D2485B458009C3FD7 /* Analytics Example */ = { + isa = PBXGroup; + children = ( + 96A12BC024B6448900949804 /* Analytics Example.entitlements */, + 96EC5699248855F800B636AC /* Controllers */, + 96D0441E2485B458009C3FD7 /* AppDelegate.swift */, + 96D044272485B459009C3FD7 /* Assets.xcassets */, + 96D0442C2485B459009C3FD7 /* Info.plist */, + 96D044292485B459009C3FD7 /* LaunchScreen.storyboard */, + 96D044242485B458009C3FD7 /* Main.storyboard */, + 96D044202485B458009C3FD7 /* SceneDelegate.swift */, + ); + path = "Analytics Example"; + sourceTree = ""; + }; + 96D0443F2485B541009C3FD7 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + 96EC5699248855F800B636AC /* Controllers */ = { + isa = PBXGroup; + children = ( + 961D80BC24902143007C4F04 /* AnonymousViewController.swift */, + 9616DB5A2490583800F7191B /* InviteViewController.swift */, + 96EC569A2488567500B636AC /* LoginViewController.swift */, + 96BC0E4B24A693E3000AF2EB /* SignInViewController.swift */, + 96BC0E4924A57317000AF2EB /* SignoutViewController.swift */, + 9616DB58249050A600F7191B /* SignupViewController.swift */, + 96D044222485B458009C3FD7 /* StartViewController.swift */, + 96EC569C2488568D00B636AC /* StepsViewController.swift */, + 96BC0E5024AA72F6000AF2EB /* TrialEndViewController.swift */, + ); + path = Controllers; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 96D0441A2485B458009C3FD7 /* Analytics Example */ = { + isa = PBXNativeTarget; + buildConfigurationList = 96D0442F2485B459009C3FD7 /* Build configuration list for PBXNativeTarget "Analytics Example" */; + buildPhases = ( + 96D044172485B458009C3FD7 /* Sources */, + 96D044182485B458009C3FD7 /* Frameworks */, + 96D044192485B458009C3FD7 /* Resources */, + 96D044422485B541009C3FD7 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Analytics Example"; + packageProductDependencies = ( + 961C616924BE58FE00A8B8E3 /* Analytics */, + ); + productName = "Analytics Example"; + productReference = 96D0441B2485B458009C3FD7 /* Analytics Example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 96D044132485B458009C3FD7 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1150; + LastUpgradeCheck = 1150; + ORGANIZATIONNAME = "Cody Garvin"; + TargetAttributes = { + 96D0441A2485B458009C3FD7 = { + CreatedOnToolsVersion = 11.5; + }; + }; + }; + buildConfigurationList = 96D044162485B458009C3FD7 /* Build configuration list for PBXProject "Analytics Example" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 96D044122485B458009C3FD7; + packageReferences = ( + 961C616824BE58FE00A8B8E3 /* XCRemoteSwiftPackageReference "analytics-ios" */, + ); + productRefGroup = 96D0441C2485B458009C3FD7 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 96D0441A2485B458009C3FD7 /* Analytics Example */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 96D044192485B458009C3FD7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 96D0442B2485B459009C3FD7 /* LaunchScreen.storyboard in Resources */, + 96D044282485B459009C3FD7 /* Assets.xcassets in Resources */, + 96D044262485B458009C3FD7 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 96D044172485B458009C3FD7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 96EC569B2488567500B636AC /* LoginViewController.swift in Sources */, + 96BC0E4A24A57317000AF2EB /* SignoutViewController.swift in Sources */, + 96BC0E5124AA72F6000AF2EB /* TrialEndViewController.swift in Sources */, + 9616DB59249050A600F7191B /* SignupViewController.swift in Sources */, + 96D044232485B458009C3FD7 /* StartViewController.swift in Sources */, + 9616DB5B2490583800F7191B /* InviteViewController.swift in Sources */, + 96D0441F2485B458009C3FD7 /* AppDelegate.swift in Sources */, + 96D044212485B458009C3FD7 /* SceneDelegate.swift in Sources */, + 961D80C024902143007C4F04 /* AnonymousViewController.swift in Sources */, + 96BC0E4C24A693E3000AF2EB /* SignInViewController.swift in Sources */, + 96EC569D2488568D00B636AC /* StepsViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 96D044242485B458009C3FD7 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 96D044252485B458009C3FD7 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 96D044292485B459009C3FD7 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 96D0442A2485B459009C3FD7 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 96D0442D2485B459009C3FD7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.5; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 96D0442E2485B459009C3FD7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.5; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 96D044302485B459009C3FD7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = "Analytics Example/Analytics Example.entitlements"; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); + INFOPLIST_FILE = "Analytics Example/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.Segment.Analytics-Example"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SUPPORTS_MACCATALYST = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 96D044312485B459009C3FD7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = "Analytics Example/Analytics Example.entitlements"; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); + INFOPLIST_FILE = "Analytics Example/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.Segment.Analytics-Example"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SUPPORTS_MACCATALYST = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 96D044162485B458009C3FD7 /* Build configuration list for PBXProject "Analytics Example" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 96D0442D2485B459009C3FD7 /* Debug */, + 96D0442E2485B459009C3FD7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 96D0442F2485B459009C3FD7 /* Build configuration list for PBXNativeTarget "Analytics Example" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 96D044302485B459009C3FD7 /* Debug */, + 96D044312485B459009C3FD7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 961C616824BE58FE00A8B8E3 /* XCRemoteSwiftPackageReference "analytics-ios" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/segmentio/analytics-ios.git"; + requirement = { + branch = migs647/macconversion; + kind = branch; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 961C616924BE58FE00A8B8E3 /* Analytics */ = { + isa = XCSwiftPackageProductDependency; + package = 961C616824BE58FE00A8B8E3 /* XCRemoteSwiftPackageReference "analytics-ios" */; + productName = Analytics; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 96D044132485B458009C3FD7 /* Project object */; +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Examples/FullExampleFlowCatalyst/Analytics Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Examples/FullExampleFlowCatalyst/Analytics Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/FullExampleFlowCatalyst/Analytics Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 000000000..0f9179535 --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "Analytics", + "repositoryURL": "https://github.com/segmentio/analytics-ios.git", + "state": { + "branch": "migs647/macconversion", + "revision": "af24593f99aece20a54ea855ff8220acd5ab01fd", + "version": null + } + } + ] + }, + "version": 1 +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Analytics Example.entitlements b/Examples/FullExampleFlowCatalyst/Analytics Example/Analytics Example.entitlements new file mode 100644 index 000000000..ee95ab7e5 --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Analytics Example.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.network.client + + + diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/AppDelegate.swift b/Examples/FullExampleFlowCatalyst/Analytics Example/AppDelegate.swift new file mode 100644 index 000000000..8f4a0e8be --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/AppDelegate.swift @@ -0,0 +1,43 @@ +// +// AppDelegate.swift +// Analytics Example +// +// Created by Cody Garvin on 6/1/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import UIKit +import Analytics + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + let configuration = AnalyticsConfiguration(writeKey: "8XpdAWa7qJVBJMK8V4FfXQOrnvCzu3Ie") + + // Enable this to record certain application events automatically! + configuration.trackApplicationLifecycleEvents = true + // Enable this to record screen views automatically! + configuration.recordScreenViews = true + Analytics.setup(with: configuration) + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/AppIcon.appiconset/Contents.json b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..831a94286 --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,101 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "Icon_120.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "Icon_180.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "filename" : "Icon.png", + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/AppIcon.appiconset/Icon.png b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/AppIcon.appiconset/Icon.png new file mode 100644 index 000000000..27e190425 Binary files /dev/null and b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/AppIcon.appiconset/Icon.png differ diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/AppIcon.appiconset/Icon_120.png b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/AppIcon.appiconset/Icon_120.png new file mode 100644 index 000000000..408a7ccf7 Binary files /dev/null and b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/AppIcon.appiconset/Icon_120.png differ diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/AppIcon.appiconset/Icon_180.png b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/AppIcon.appiconset/Icon_180.png new file mode 100644 index 000000000..55966b3b6 Binary files /dev/null and b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/AppIcon.appiconset/Icon_180.png differ diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/Contents.json b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/SegmentLogo.imageset/Contents.json b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/SegmentLogo.imageset/Contents.json new file mode 100644 index 000000000..d7353623d --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/SegmentLogo.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "Segment_Logo.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Segment_Logo@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/SegmentLogo.imageset/Segment_Logo.png b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/SegmentLogo.imageset/Segment_Logo.png new file mode 100644 index 000000000..5fd84c712 Binary files /dev/null and b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/SegmentLogo.imageset/Segment_Logo.png differ diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/SegmentLogo.imageset/Segment_Logo@2x.png b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/SegmentLogo.imageset/Segment_Logo@2x.png new file mode 100644 index 000000000..b90a0ee20 Binary files /dev/null and b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/SegmentLogo.imageset/Segment_Logo@2x.png differ diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/Splash.imageset/Contents.json b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/Splash.imageset/Contents.json new file mode 100644 index 000000000..e5cd8ada4 --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/Splash.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Splash.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/Splash.imageset/Splash.png b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/Splash.imageset/Splash.png new file mode 100644 index 000000000..9057e4473 Binary files /dev/null and b/Examples/FullExampleFlowCatalyst/Analytics Example/Assets.xcassets/Splash.imageset/Splash.png differ diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Base.lproj/LaunchScreen.storyboard b/Examples/FullExampleFlowCatalyst/Analytics Example/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..3815be6fb --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Base.lproj/Main.storyboard b/Examples/FullExampleFlowCatalyst/Analytics Example/Base.lproj/Main.storyboard new file mode 100644 index 000000000..205a35644 --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Base.lproj/Main.storyboard @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/AnonymousViewController.swift b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/AnonymousViewController.swift new file mode 100644 index 000000000..12b002204 --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/AnonymousViewController.swift @@ -0,0 +1,75 @@ +// +// AnonymousViewController.swift +// Analytics Example +// +// Created by Cody Garvin on 6/3/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import UIKit +import Analytics + +class AnonymousViewController: StepsViewController { + + let anonymousUserID = "70e4ab26-3c4d-42c9-aed1-2c186738a97d" + + private var continueButton: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + + descriptionString = "Login with details using identify" + codeString = """ +// Start with the analytics singleton +let analytics = Analytics.shared() + +// identify screen load (sends anonymous id) +analytics.screen("Home") + +// identify with anonymous user +analytics.identify(nil, traits: ["subscription": "inactive"]) + +// track CTA tap (sends anonymous id) +analytics.track("CTA Tapped", properties: ["plan": "premium"]) +""" + + // Add the button + let trackButton = UIButton.SegmentButton("Track", target: self, action: #selector(trackUser(_:))) + continueButton = UIButton.SegmentButton("Continue", target: self, action: #selector(continueToNext(_:))) + continueButton.isEnabled = false + + propertyViews = [trackButton, UIView.separator(), continueButton, UIView.separator()] + + // Fire off the beginning analytics + startAnalytics() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + continueButton.isEnabled = false + } + + private func startAnalytics() { + let analytics = Analytics.shared() + + // identify screen load + analytics.screen("Home") + + // identify anonymous user + analytics.identify(nil, traits: ["subscription": "inactive"]) + } + + @objc + private func trackUser(_ sender: Any) { + let analytics = Analytics.shared() + // track CTA tap + analytics.track("CTA Tapped", properties: ["plan": "premium"]) + + continueButton.isEnabled = true + } + + @objc private func continueToNext(_ sender: Any) { + let signup = SignupViewController(nibName: nil, bundle: nil) + navigationController?.pushViewController(signup, animated: true) + } +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/InviteViewController.swift b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/InviteViewController.swift new file mode 100644 index 000000000..69687f9b0 --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/InviteViewController.swift @@ -0,0 +1,63 @@ +// +// InviteViewController.swift +// Analytics Example +// +// Created by Cody Garvin on 6/25/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import UIKit +import Analytics + +class InviteViewController: StepsViewController { + + private var continueButton: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + + descriptionString = "Login with details using identify" + codeString = """ +// Start with the analytics singleton +let analytics = Analytics.shared() + +// Screen +analytics.screen("Invite") + +// Invite user +analytics.track("Invite Sent", properties: ["first": "Jane", "last": "Doe", "email": "jane@abc.com"]) +""" + + // Add the button + let inviteButton = UIButton.SegmentButton("Invite Yser", target: self, action: #selector(createUser(_:))) + continueButton = UIButton.SegmentButton("Continue", target: self, action: #selector(continueToNext(_:))) + continueButton.isEnabled = false + + propertyViews = [inviteButton, UIView.separator(), continueButton, UIView.separator()] + + // Fire off the beginning analytics + startAnalytics() + } + + private + func startAnalytics() { + let analytics = Analytics.shared() + + // identify screen load + analytics.screen("Invite") + } + + @objc + func createUser(_ sender: Any) { + let analytics = Analytics.shared() + // track CTA tap + analytics.track("Invite Sent", properties: ["first": "Jane", "last": "Doe", "email": "jane@abc.com"]) + continueButton.isEnabled = true + } + + @objc + func continueToNext(_ sender: Any) { + let signoutVC = SignoutViewController(nibName: nil, bundle: nil) + navigationController?.pushViewController(signoutVC, animated: true) + } +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/LoginViewController.swift b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/LoginViewController.swift new file mode 100644 index 000000000..d69eb7f0f --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/LoginViewController.swift @@ -0,0 +1,27 @@ +// +// LoginViewController.swift +// Analytics Example +// +// Created by Cody Garvin on 6/3/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import UIKit + +class LoginViewController: StepsViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + title = "Login Example" + descriptionString = "Login with details using identify" + codeString = """ +// Start by identifying the user +if let analytics = Analytics.shared() +Analytics.shared().identify("1234", + traits: ["email": "jack@segment.com", + "phone": "555-444-3333"]) +""" + } +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/SignInViewController.swift b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/SignInViewController.swift new file mode 100644 index 000000000..39fcfedb7 --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/SignInViewController.swift @@ -0,0 +1,63 @@ +// +// SigninViewController.swift +// Analytics Example +// +// Created by Cody Garvin on 6/9/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import UIKit +import Analytics + +class SigninViewController: StepsViewController { + + private var continueButton: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + + descriptionString = "Login with details using identify" + codeString = """ +// Start with the analytics singleton +let analytics = Analytics.shared() + +// Screen +analytics.screen("Dashboard") + +// Signed in +analytics.track("Signed In", properties: ["username": "pgibbons"]) +""" + + // Add the button + let signinButton = UIButton.SegmentButton("Sign In", target: self, action: #selector(signin(_:))) + continueButton = UIButton.SegmentButton("Continue", target: self, action: #selector(continueToNext(_:))) + continueButton.isEnabled = false + + propertyViews = [signinButton, UIView.separator(), continueButton, UIView.separator()] + + // Fire off the beginning analytics + startAnalytics() + } + + private + func startAnalytics() { + let analytics = Analytics.shared() + + // identify screen load + analytics.screen("Dashboard") + } + + @objc + func signin(_ sender: Any) { + let analytics = Analytics.shared() + // track CTA tap + analytics.track("Signed In", properties: ["username": "pgibbons"]) + continueButton.isEnabled = true + } + + @objc + func continueToNext(_ sender: Any) { + let trailEndVC = TrialEndViewController(nibName: nil, bundle: nil) + navigationController?.pushViewController(trailEndVC, animated: true) + } +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/SignoutViewController.swift b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/SignoutViewController.swift new file mode 100644 index 000000000..3672c5998 --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/SignoutViewController.swift @@ -0,0 +1,63 @@ +// +// SignoutViewController.swift +// Analytics Example +// +// Created by Cody Garvin on 6/9/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import UIKit +import Analytics + +class SignoutViewController: StepsViewController { + + private var continueButton: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + + descriptionString = "Login with details using identify" + codeString = """ +// Start with the analytics singleton +let analytics = Analytics.shared() + +// Screen +analytics.screen("Signout") + +// Signout user +analytics.track("Signed Out", properties: ["username": "pgibbons"]) +""" + + // Add the button + let signoutButton = UIButton.SegmentButton("Signout", target: self, action: #selector(signout(_:))) + continueButton = UIButton.SegmentButton("Continue", target: self, action: #selector(continueToNext(_:))) + continueButton.isEnabled = false + + propertyViews = [signoutButton, UIView.separator(), continueButton, UIView.separator()] + + // Fire off the beginning analytics + startAnalytics() + } + + private + func startAnalytics() { + let analytics = Analytics.shared() + + // identify screen load + analytics.screen("Signout") + } + + @objc + func signout(_ sender: Any) { + let analytics = Analytics.shared() + // track CTA tap + analytics.track("Signed Out", properties: ["username": "pgibbons"]) + continueButton.isEnabled = true + } + + @objc + func continueToNext(_ sender: Any) { + let signinVC = SigninViewController(nibName: nil, bundle: nil) + navigationController?.pushViewController(signinVC, animated: true) + } +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/SignupViewController.swift b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/SignupViewController.swift new file mode 100644 index 000000000..14050cd41 --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/SignupViewController.swift @@ -0,0 +1,81 @@ +// +// SignupViewController.swift +// Analytics Example +// +// Created by Cody Garvin on 6/9/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import UIKit +import Analytics + +class SignupViewController: StepsViewController { + + private var continueButton: UIButton! + private var trackButton: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + + descriptionString = "Login with details using identify" + codeString = """ +// Start with the analytics singleton +let analytics = Analytics.shared() + +// Screen +analytics.screen("Signup") + +// create user +analytics.track("Create Account", properties: ["Signed Up": ...]) + +// Alias new user id with anonymous id +analytics.alias("AA-BB-CC-NEW-ID") + +// Start trial +analytics.track("Trial Started", properties: ...) +""" + + // Add the button + let createButton = UIButton.SegmentButton("Create Account", target: self, action: #selector(createUser(_:))) + trackButton = UIButton.SegmentButton("Start Trial", target: self, action: #selector(trackUser(_:))) + trackButton.isEnabled = false + continueButton = UIButton.SegmentButton("Continue", target: self, action: #selector(continueToNext(_:))) + continueButton.isEnabled = false + + propertyViews = [createButton, UIView.separator(), trackButton, UIView.separator(), continueButton, UIView.separator()] + + // Fire off the beginning analytics + startAnalytics() + } + + private + func startAnalytics() { + let analytics = Analytics.shared() + + // identify screen load + analytics.screen("Signup") + } + + @objc + func createUser(_ sender: Any) { + let analytics = Analytics.shared() + // track CTA tap + analytics.track("Create Account", properties: ["Signed Up": ["first": "Peter", "last": "Gibbons", "phone": "pgibbons"]]) + analytics.alias("AA-BB-CC-NEW-ID") + trackButton.isEnabled = true + } + + @objc func trackUser(_ sender: Any) { + let analytics = Analytics.shared() + // track user + analytics.track("Trial Started", properties: ["start_date": "2018-08-27"]) + + continueButton.isEnabled = true + } + + @objc + func continueToNext(_ sender: Any) { + let invite = InviteViewController(nibName: nil, bundle: nil) + navigationController?.pushViewController(invite, animated: true) + } +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/StartViewController.swift b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/StartViewController.swift new file mode 100644 index 000000000..99a42a0fb --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/StartViewController.swift @@ -0,0 +1,96 @@ +// +// ViewController.swift +// Analytics Example +// +// Created by Cody Garvin on 6/1/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import UIKit +import Analytics + +class StartViewController: UIViewController { + + @IBOutlet weak var tableView: UITableView! + @IBOutlet weak var writeKeyField: UITextField! + + private var storedKeys: Array? + + + override func viewDidLoad() { + super.viewDidLoad() + + title = "Start" + + // Do any additional setup after loading the view. + tableView.register(UITableViewCell.self, forCellReuseIdentifier: "writeKeyCell") + + storedKeys = storedWriteKeys() + + Analytics.shared().flush() + } + + @IBAction + func login(_ sender: Any) { + + // Grab the current write key + guard let writeKey = writeKeyField.text else { return } + + // Store off the current write key + saveWriteKey(writeKey) + + let loginController = LoginViewController() + self.navigationController?.pushViewController(loginController, animated: true) + } + + private func storedWriteKeys() -> Array? { + var returnKeys: Array? + + if let existingKeys = UserDefaults.standard.object(forKey: "writekeys") as? Array { + returnKeys = existingKeys + } + + return returnKeys + } + + private func saveWriteKey(_ key: String) { + var writeKeys = [key] + if let keys = storedWriteKeys() { + + if !keys.contains(key) { + writeKeys.append(contentsOf: keys) + } else { + return + } + } + + UserDefaults.standard.set(writeKeys, forKey: "writekeys") + } +} + +extension StartViewController: UITableViewDataSource, UITableViewDelegate { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return storedWriteKeys()?.count ?? 0 + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let returnCell = tableView.dequeueReusableCell(withIdentifier: "writeKeyCell") else { + return UITableViewCell() + } + returnCell.textLabel?.text = storedKeys?[indexPath.row] + returnCell.textLabel?.font = UIFont.systemFont(ofSize: 12.0) + return returnCell + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + // Grab key from index + writeKeyField.text = storedKeys?[indexPath.row] + } + + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + return "Write Keys" + } +} + diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/StepsViewController.swift b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/StepsViewController.swift new file mode 100644 index 000000000..99e4c778c --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/StepsViewController.swift @@ -0,0 +1,154 @@ +// +// StepsViewController.swift +// Analytics Example +// +// Created by Cody Garvin on 6/3/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import UIKit + +class StepsViewController: UIViewController { + + var codeString: String? { + didSet { + codeView.text = codeString + } + } + + var descriptionString: String? { + didSet { + descriptionView.text = descriptionString + } + } + + var propertyViews: [UIView]? { + didSet { + stackView.removeFromSuperview() + setup() + } + } + + private var codeView: UITextView! + private var descriptionView: UILabel! + private var stackView: UIStackView! + + override func viewDidLoad() { + super.viewDidLoad() + + // Titlebar setup + titleBarSetup() + + // Do any additional setup after loading the view. + setup() + } + + private func titleBarSetup() { + + let titleImageView = UIImageView(image: UIImage(named: "SegmentLogo")) + titleImageView.frame = CGRect(x: 0, y: 0, width: 193.0, height: 40.0) + titleImageView.contentMode = .scaleAspectFit + navigationItem.titleView = titleImageView + } + + private func setup() { + view.backgroundColor = UIColor.white + + stackView = UIStackView() + stackView.axis = .vertical + stackView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(stackView) + stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16.0).isActive = true + stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16.0).isActive = true + stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16.0).isActive = true + stackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -16.0).isActive = true + stackView.alignment = .leading + + if let propertyViews = propertyViews { + for (count, view) in propertyViews.enumerated() { + stackView.insertArrangedSubview(view, at: count) + view.widthAnchor.constraint(equalTo: stackView.widthAnchor).isActive = true + } + } + + let containerView = UIView(frame: .zero) + containerView.translatesAutoresizingMaskIntoConstraints = false + + descriptionView = UILabel(frame: .zero) + descriptionView.translatesAutoresizingMaskIntoConstraints = false + containerView.addSubview(descriptionView) + descriptionView.font = UIFont.systemFont(ofSize: 14.0) + descriptionView.textColor = UIColor.primaryColor02() + descriptionView.topAnchor.constraint(equalTo: containerView.safeAreaLayoutGuide.topAnchor).isActive = true + descriptionView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true + descriptionView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true + descriptionView.numberOfLines = 0 + descriptionView.text = descriptionString + + codeView = UITextView(frame: .zero) + codeView.translatesAutoresizingMaskIntoConstraints = false + containerView.addSubview(codeView) + codeView.font = UIFont(name: "Menlo-Regular", size: 12.0) + codeView.textColor = UIColor.primaryColor02() + codeView.translatesAutoresizingMaskIntoConstraints = false + codeView.topAnchor.constraint(equalTo: descriptionView.bottomAnchor, constant: 16.0).isActive = true + codeView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true + codeView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true + codeView.bottomAnchor.constraint(equalTo: containerView.safeAreaLayoutGuide.bottomAnchor).isActive = true + codeView.layer.borderColor = UIColor.primaryColor02().cgColor // 18 / 66 / 74 + codeView.layer.cornerRadius = 6.0 + codeView.text = codeString + + codeView.layer.borderWidth = 1.0 + codeView.backgroundColor = UIColor.secondaryColor01() // 204 / 217 / 222 + + stackView.addArrangedSubview(containerView) + containerView.widthAnchor.constraint(equalTo: stackView.widthAnchor).isActive = true + + // Theme + navigationController?.navigationBar.tintColor = UIColor.primaryColor01() + } +} + +extension UIColor { + // 204/217/222 + static func secondaryColor01() -> UIColor { + return UIColor(red: 0.8, green: 0.85, blue: 0.87, alpha: 1.0) + } + + // 18/66/74 + static func primaryColor02() -> UIColor { + return UIColor(red: 0.07, green: 0.26, blue: 0.29, alpha: 1.0) + } + + // 82 / 189 / 149 + static func primaryColor01() -> UIColor { + return UIColor(red: 0.32, green: 0.74, blue: 0.58, alpha: 1.0) + } + +} + +extension UIButton { + static func SegmentButton(_ title: String, target: Any, action: Selector) -> UIButton { + let trackButton = UIButton() + trackButton.setTitle(title, for: .normal) + trackButton.setTitleColor(UIColor.primaryColor02(), for: .normal) + trackButton.setTitleColor(UIColor.lightGray, for: .disabled) + trackButton.addTarget(target, action: action, for: .touchUpInside) + trackButton.titleLabel?.textColor = UIColor.primaryColor02() + trackButton.layer.borderColor = UIColor.primaryColor02().cgColor + trackButton.layer.borderWidth = 1.0 + trackButton.layer.cornerRadius = 6.0 + trackButton.contentEdgeInsets = UIEdgeInsets(top: 6, left: 8, bottom: 6, right: 8) + return trackButton + } +} + +extension UIView { + static func separator() -> UIView { + let separator = UIView() + separator.heightAnchor.constraint(equalToConstant: 12.0).isActive = true + separator.backgroundColor = .white + return separator + } +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/TrialEndViewController.swift b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/TrialEndViewController.swift new file mode 100644 index 000000000..6d68739ea --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Controllers/TrialEndViewController.swift @@ -0,0 +1,84 @@ +// +// TrialEndViewController.swift +// Analytics Example +// +// Created by Cody Garvin on 6/29/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import UIKit +import Analytics + +class TrialEndViewController: StepsViewController { + + let anonymousUserID = "70e4ab26-3c4d-42c9-aed1-2c186738a97d" + + private var continueButton: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + + descriptionString = "Login with details using identify" + codeString = """ +// Start with the analytics singleton +let analytics = Analytics.shared() + +// identify screen load +analytics.screen("Dashboard") + +// identify anonymous user +analytics.track("Trial Ended", properties: [...]) + +// track delete request +analytics.track("Account Delete request", properties: ["account_id": "AA-BB-CC-USER-ID"]) + +// removed user +analytics.track("Account Deleted", properties: ["username": "pgibbons", "account_id": "AA-BB-CC-USER-ID"]) + +// Signed out +analytics.track("Signed Out", properties: ["username": "pgibbons"]) +""" + + // Add the button + let deleteButton = UIButton.SegmentButton("Request Delete Account", target: self, action: #selector(deleteUser(_:))) + continueButton = UIButton.SegmentButton("Done", target: self, action: #selector(continueToNext(_:))) + continueButton.isEnabled = false + + propertyViews = [deleteButton, UIView.separator(), continueButton, UIView.separator()] + + // Fire off the beginning analytics + startAnalytics() + } + + private func startAnalytics() { + let analytics = Analytics.shared() + + // identify screen load + analytics.screen("Dashboard") + + // identify anonymous user + analytics.track("Trial Ended", properties: ["trial_start": "2020-06-29", "trial_end": "2020-06-30", "trial_plan": "premium"]) + } + + @objc + private func deleteUser(_ sender: Any) { + let analytics = Analytics.shared() + // track delete request + analytics.track("Account Delete request", properties: ["account_id": "AA-BB-CC-USER-ID"]) + + // Some async request + DispatchQueue.global().async { + // removed user + analytics.track("Account Deleted", properties: ["username": "pgibbons", "account_id": "AA-BB-CC-USER-ID"]) + // Signed out + analytics.track("Signed Out", properties: ["username": "pgibbons"]) + DispatchQueue.main.async { + self.continueButton.isEnabled = true + } + } + } + + @objc private func continueToNext(_ sender: Any) { + navigationController?.popToRootViewController(animated: true) + } +} diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/Info.plist b/Examples/FullExampleFlowCatalyst/Analytics Example/Info.plist new file mode 100644 index 000000000..2a3483c0d --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/Info.plist @@ -0,0 +1,64 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Examples/FullExampleFlowCatalyst/Analytics Example/SceneDelegate.swift b/Examples/FullExampleFlowCatalyst/Analytics Example/SceneDelegate.swift new file mode 100644 index 000000000..aae7896aa --- /dev/null +++ b/Examples/FullExampleFlowCatalyst/Analytics Example/SceneDelegate.swift @@ -0,0 +1,53 @@ +// +// SceneDelegate.swift +// Analytics Example +// +// Created by Cody Garvin on 6/1/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + diff --git a/Examples/SegmentMac/SegmentMac.xcodeproj/project.pbxproj b/Examples/SegmentMac/SegmentMac.xcodeproj/project.pbxproj new file mode 100644 index 000000000..097eb5d26 --- /dev/null +++ b/Examples/SegmentMac/SegmentMac.xcodeproj/project.pbxproj @@ -0,0 +1,381 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 961C616D24BE5BA200A8B8E3 /* Analytics in Frameworks */ = {isa = PBXBuildFile; productRef = 961C616C24BE5BA200A8B8E3 /* Analytics */; }; + 96A12BAE24B3AEE200949804 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96A12BAD24B3AEE200949804 /* AppDelegate.swift */; }; + 96A12BB024B3AEE200949804 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96A12BAF24B3AEE200949804 /* ViewController.swift */; }; + 96A12BB224B3AEE400949804 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 96A12BB124B3AEE400949804 /* Assets.xcassets */; }; + 96A12BB524B3AEE400949804 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 96A12BB324B3AEE400949804 /* Main.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 96A12C2524B65F5F00949804 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 96A12BAA24B3AEE200949804 /* SegmentMac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SegmentMac.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 96A12BAD24B3AEE200949804 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 96A12BAF24B3AEE200949804 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 96A12BB124B3AEE400949804 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 96A12BB424B3AEE400949804 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 96A12BB624B3AEE400949804 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 96A12BB724B3AEE400949804 /* SegmentMac.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SegmentMac.entitlements; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 96A12BA724B3AEE200949804 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 961C616D24BE5BA200A8B8E3 /* Analytics in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 96A12BA124B3AEE200949804 = { + isa = PBXGroup; + children = ( + 96A12BAC24B3AEE200949804 /* SegmentMac */, + 96A12BAB24B3AEE200949804 /* Products */, + 96A12C0B24B65C4C00949804 /* Frameworks */, + ); + sourceTree = ""; + }; + 96A12BAB24B3AEE200949804 /* Products */ = { + isa = PBXGroup; + children = ( + 96A12BAA24B3AEE200949804 /* SegmentMac.app */, + ); + name = Products; + sourceTree = ""; + }; + 96A12BAC24B3AEE200949804 /* SegmentMac */ = { + isa = PBXGroup; + children = ( + 96A12BAD24B3AEE200949804 /* AppDelegate.swift */, + 96A12BAF24B3AEE200949804 /* ViewController.swift */, + 96A12BB124B3AEE400949804 /* Assets.xcassets */, + 96A12BB324B3AEE400949804 /* Main.storyboard */, + 96A12BB624B3AEE400949804 /* Info.plist */, + 96A12BB724B3AEE400949804 /* SegmentMac.entitlements */, + ); + path = SegmentMac; + sourceTree = ""; + }; + 96A12C0B24B65C4C00949804 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 96A12BA924B3AEE200949804 /* SegmentMac */ = { + isa = PBXNativeTarget; + buildConfigurationList = 96A12BBA24B3AEE400949804 /* Build configuration list for PBXNativeTarget "SegmentMac" */; + buildPhases = ( + 96A12BA624B3AEE200949804 /* Sources */, + 96A12BA724B3AEE200949804 /* Frameworks */, + 96A12BA824B3AEE200949804 /* Resources */, + 96A12C2524B65F5F00949804 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SegmentMac; + packageProductDependencies = ( + 961C616C24BE5BA200A8B8E3 /* Analytics */, + ); + productName = SegmentMac; + productReference = 96A12BAA24B3AEE200949804 /* SegmentMac.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 96A12BA224B3AEE200949804 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1150; + LastUpgradeCheck = 1150; + ORGANIZATIONNAME = "Cody Garvin"; + TargetAttributes = { + 96A12BA924B3AEE200949804 = { + CreatedOnToolsVersion = 11.5; + }; + }; + }; + buildConfigurationList = 96A12BA524B3AEE200949804 /* Build configuration list for PBXProject "SegmentMac" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 96A12BA124B3AEE200949804; + packageReferences = ( + 961C616B24BE5BA200A8B8E3 /* XCRemoteSwiftPackageReference "analytics-ios" */, + ); + productRefGroup = 96A12BAB24B3AEE200949804 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 96A12BA924B3AEE200949804 /* SegmentMac */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 96A12BA824B3AEE200949804 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 96A12BB224B3AEE400949804 /* Assets.xcassets in Resources */, + 96A12BB524B3AEE400949804 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 96A12BA624B3AEE200949804 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 96A12BB024B3AEE200949804 /* ViewController.swift in Sources */, + 96A12BAE24B3AEE200949804 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 96A12BB324B3AEE400949804 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 96A12BB424B3AEE400949804 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 96A12BB824B3AEE400949804 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 96A12BB924B3AEE400949804 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 96A12BBB24B3AEE400949804 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = SegmentMac/SegmentMac.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ""; + ENABLE_HARDENED_RUNTIME = YES; + INFOPLIST_FILE = SegmentMac/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.Segment.SegmentMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 96A12BBC24B3AEE400949804 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = SegmentMac/SegmentMac.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ""; + ENABLE_HARDENED_RUNTIME = YES; + INFOPLIST_FILE = SegmentMac/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.Segment.SegmentMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 96A12BA524B3AEE200949804 /* Build configuration list for PBXProject "SegmentMac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 96A12BB824B3AEE400949804 /* Debug */, + 96A12BB924B3AEE400949804 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 96A12BBA24B3AEE400949804 /* Build configuration list for PBXNativeTarget "SegmentMac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 96A12BBB24B3AEE400949804 /* Debug */, + 96A12BBC24B3AEE400949804 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 961C616B24BE5BA200A8B8E3 /* XCRemoteSwiftPackageReference "analytics-ios" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/segmentio/analytics-ios.git"; + requirement = { + branch = migs647/macconversion; + kind = branch; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 961C616C24BE5BA200A8B8E3 /* Analytics */ = { + isa = XCSwiftPackageProductDependency; + package = 961C616B24BE5BA200A8B8E3 /* XCRemoteSwiftPackageReference "analytics-ios" */; + productName = Analytics; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 96A12BA224B3AEE200949804 /* Project object */; +} diff --git a/Examples/SegmentMac/SegmentMac.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Examples/SegmentMac/SegmentMac.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Examples/SegmentMac/SegmentMac.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Examples/SegmentMac/SegmentMac.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Examples/SegmentMac/SegmentMac.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Examples/SegmentMac/SegmentMac.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Examples/SegmentMac/SegmentMac.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/SegmentMac/SegmentMac.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 000000000..5302431a3 --- /dev/null +++ b/Examples/SegmentMac/SegmentMac.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "Analytics", + "repositoryURL": "https://github.com/segmentio/analytics-ios.git", + "state": { + "branch": "migs647/macconversion", + "revision": "bd012c2c3fe26e228bdf386a7e38c0a6b4b761fc", + "version": null + } + } + ] + }, + "version": 1 +} diff --git a/Examples/SegmentMac/SegmentMac/AppDelegate.swift b/Examples/SegmentMac/SegmentMac/AppDelegate.swift new file mode 100644 index 000000000..ec0d1e83d --- /dev/null +++ b/Examples/SegmentMac/SegmentMac/AppDelegate.swift @@ -0,0 +1,24 @@ +// +// AppDelegate.swift +// SegmentMac +// +// Created by Cody Garvin on 7/6/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import Cocoa + +@NSApplicationMain +class AppDelegate: NSObject, NSApplicationDelegate { + + func applicationDidFinishLaunching(_ aNotification: Notification) { + // Insert code here to initialize your application + } + + func applicationWillTerminate(_ aNotification: Notification) { + // Insert code here to tear down your application + } + + +} + diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Contents.json b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..b3f2e5f2f --- /dev/null +++ b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "filename" : "Segment_Logo-16.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "filename" : "Segment_Logo-33.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "filename" : "Segment_Logo-32.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "filename" : "Segment_Logo-64.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "filename" : "Segment_Logo-128.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "filename" : "Segment_Logo-257.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "filename" : "Segment_Logo-256.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "filename" : "Segment_Logo-513.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "filename" : "Segment_Logo-512.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "filename" : "Segment_Logo-1024.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-1024.png b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-1024.png new file mode 100644 index 000000000..b571a315b Binary files /dev/null and b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-1024.png differ diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-128.png b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-128.png new file mode 100644 index 000000000..756601ce5 Binary files /dev/null and b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-128.png differ diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-16.png b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-16.png new file mode 100644 index 000000000..6bbce0ec7 Binary files /dev/null and b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-16.png differ diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-256.png b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-256.png new file mode 100644 index 000000000..0e0993ddc Binary files /dev/null and b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-256.png differ diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-257.png b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-257.png new file mode 100644 index 000000000..0e0993ddc Binary files /dev/null and b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-257.png differ diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-32.png b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-32.png new file mode 100644 index 000000000..cb1a61adf Binary files /dev/null and b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-32.png differ diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-33.png b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-33.png new file mode 100644 index 000000000..cb1a61adf Binary files /dev/null and b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-33.png differ diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-512.png b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-512.png new file mode 100644 index 000000000..490efeba7 Binary files /dev/null and b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-512.png differ diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-513.png b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-513.png new file mode 100644 index 000000000..490efeba7 Binary files /dev/null and b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-513.png differ diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-64.png b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-64.png new file mode 100644 index 000000000..830c793ba Binary files /dev/null and b/Examples/SegmentMac/SegmentMac/Assets.xcassets/AppIcon.appiconset/Segment_Logo-64.png differ diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/Contents.json b/Examples/SegmentMac/SegmentMac/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Examples/SegmentMac/SegmentMac/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/Segment_Log.imageset/Contents.json b/Examples/SegmentMac/SegmentMac/Assets.xcassets/Segment_Log.imageset/Contents.json new file mode 100644 index 000000000..6673e06de --- /dev/null +++ b/Examples/SegmentMac/SegmentMac/Assets.xcassets/Segment_Log.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Segment_Log.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/SegmentMac/SegmentMac/Assets.xcassets/Segment_Log.imageset/Segment_Log.png b/Examples/SegmentMac/SegmentMac/Assets.xcassets/Segment_Log.imageset/Segment_Log.png new file mode 100644 index 000000000..0bb6a66d9 Binary files /dev/null and b/Examples/SegmentMac/SegmentMac/Assets.xcassets/Segment_Log.imageset/Segment_Log.png differ diff --git a/Examples/SegmentMac/SegmentMac/Base.lproj/Main.storyboard b/Examples/SegmentMac/SegmentMac/Base.lproj/Main.storyboard new file mode 100644 index 000000000..00138b032 --- /dev/null +++ b/Examples/SegmentMac/SegmentMac/Base.lproj/Main.storyboard @@ -0,0 +1,777 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/SegmentMac/SegmentMac/Info.plist b/Examples/SegmentMac/SegmentMac/Info.plist new file mode 100644 index 000000000..a8959609d --- /dev/null +++ b/Examples/SegmentMac/SegmentMac/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2020 Cody Garvin. All rights reserved. + NSMainStoryboardFile + Main + NSPrincipalClass + NSApplication + NSSupportsAutomaticTermination + + NSSupportsSuddenTermination + + + diff --git a/Examples/SegmentMac/SegmentMac/SegmentMac.entitlements b/Examples/SegmentMac/SegmentMac/SegmentMac.entitlements new file mode 100644 index 000000000..40b639e46 --- /dev/null +++ b/Examples/SegmentMac/SegmentMac/SegmentMac.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + com.apple.security.network.client + + com.apple.security.network.server + + + diff --git a/Examples/SegmentMac/SegmentMac/ViewController.swift b/Examples/SegmentMac/SegmentMac/ViewController.swift new file mode 100644 index 000000000..c6263110e --- /dev/null +++ b/Examples/SegmentMac/SegmentMac/ViewController.swift @@ -0,0 +1,57 @@ +// +// ViewController.swift +// SegmentMac +// +// Created by Cody Garvin on 7/6/20. +// Copyright © 2020 Cody Garvin. All rights reserved. +// + +import Cocoa +import Analytics + +class ViewController: NSViewController { + + @IBOutlet weak var signinButton: NSButton! + @IBOutlet weak var associateButton: NSButton! + @IBOutlet weak var signoutButton: NSButton! + + override func viewDidLoad() { + super.viewDidLoad() + + let configuration = AnalyticsConfiguration(writeKey: "8XpdAWa7qJVBJMK8V4FfXQOrnvCzu3Ie") + + // Enable this to record certain application events automatically! + configuration.trackApplicationLifecycleEvents = true + // Enable this to record screen views automatically! + configuration.recordScreenViews = true + Analytics.setup(with: configuration) + + + // Do any additional setup after loading the view. + let analytics = Analytics.shared() + + // identify screen load + analytics.screen("SegmentMac") + } + + override var representedObject: Any? { + didSet { + // Update the view, if already loaded. + } + } + + @IBAction func signinTapped(_ sender: Any) { + associateButton.isEnabled = true + Analytics.shared().track("Signed In") + } + + @IBAction func associateTapped(_ sender: Any) { + signoutButton.isEnabled = true + Analytics.shared().alias("New-Associate-ID") + } + + @IBAction func signoutTapped(_ sender: Any) { + Analytics.shared().track("Signed Out") + } +} + diff --git a/Makefile b/Makefile index c25b9108e..b790f5462 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ lint: pod lib lint --allow-warnings carthage: - carthage build --no-skip-current + carthage build --platform ios --no-skip-current archive: carthage carthage archive Analytics diff --git a/Podfile.lock b/Podfile.lock index a4984894f..02d53b3fb 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -13,4 +13,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: b1320b7107926418d81b6d48a9c864abdf9c3eaf -COCOAPODS: 1.9.1 +COCOAPODS: 1.9.3