Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add build support for watchOS #1057

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Segment.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,9 @@
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx watchos watchsimulator";
SUPPORTS_MACCATALYST = YES;
TARGETED_DEVICE_FAMILY = "1,2,3,4";
};
name = Debug;
};
Expand All @@ -762,6 +765,9 @@
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx watchos watchsimulator";
SUPPORTS_MACCATALYST = YES;
TARGETED_DEVICE_FAMILY = "1,2,3,4";
};
name = Release;
};
Expand Down
35 changes: 31 additions & 4 deletions Segment/Classes/SEGAnalytics.m
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,17 @@ - (instancetype)initWithConfiguration:(SEGAnalyticsConfiguration *)configuration
// Pass through for application state change events
id<SEGApplicationProtocol> application = configuration.application;
if (application) {
#if TARGET_OS_IPHONE
#if TARGET_OS_WATCH
// Attach to application state change hooks
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
for (NSString *name in @[ WKApplicationDidEnterBackgroundNotification,
WKApplicationDidFinishLaunchingNotification,
WKApplicationWillEnterForegroundNotification,
WKApplicationWillResignActiveNotification,
WKApplicationDidBecomeActiveNotification ]) {
[nc addObserver:self selector:@selector(handleAppStateNotification:) name:name object:application];
}
#elif TARGET_OS_IPHONE
// Attach to application state change hooks
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
for (NSString *name in @[ UIApplicationDidEnterBackgroundNotification,
Expand All @@ -85,7 +95,7 @@ - (instancetype)initWithConfiguration:(SEGAnalyticsConfiguration *)configuration
#endif
}

#if TARGET_OS_IPHONE
#if TARGET_OS_IPHONE && !TARGET_OS_WATCH
if (configuration.recordScreenViews) {
[UIViewController seg_swizzleViewDidAppear];
}
Expand All @@ -98,7 +108,7 @@ - (instancetype)initWithConfiguration:(SEGAnalyticsConfiguration *)configuration
_storeKitTracker = [SEGStoreKitTracker trackTransactionsForAnalytics:self];
}

#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_WATCH
if (configuration.trackPushNotifications && configuration.launchOptions) {
#if TARGET_OS_IOS
NSDictionary *remoteNotification = configuration.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
Expand Down Expand Up @@ -128,7 +138,22 @@ - (void)dealloc
NSString *const SEGBuildKeyV1 = @"SEGBuildKey";
NSString *const SEGBuildKeyV2 = @"SEGBuildKeyV2";

#if TARGET_OS_IPHONE
#if TARGET_OS_WATCH
- (void)handleAppStateNotification:(NSNotification *)note
{
SEGApplicationLifecyclePayload *payload = [[SEGApplicationLifecyclePayload alloc] init];
payload.notificationName = note.name;
[self run:SEGEventTypeApplicationLifecycle payload:payload];

if ([note.name isEqualToString:WKApplicationDidFinishLaunchingNotification]) {
[self _applicationDidFinishLaunchingWithOptions:note.userInfo];
} else if ([note.name isEqualToString:WKApplicationWillEnterForegroundNotification]) {
[self _applicationWillEnterForeground];
} else if ([note.name isEqualToString:WKApplicationDidEnterBackgroundNotification]) {
[self _applicationDidEnterBackground];
}
}
#elif TARGET_OS_IPHONE
- (void)handleAppStateNotification:(NSNotification *)note
{
SEGApplicationLifecyclePayload *payload = [[SEGApplicationLifecyclePayload alloc] init];
Expand Down Expand Up @@ -198,8 +223,10 @@ - (void)_applicationDidFinishLaunchingWithOptions:(NSDictionary *)launchOptions
@"from_background" : @NO,
@"version" : currentVersion ?: @"",
@"build" : currentBuild ?: @"",
#if !TARGET_OS_WATCH
@"referring_application" : launchOptions[UIApplicationLaunchOptionsSourceApplicationKey] ?: @"",
@"url" : launchOptions[UIApplicationLaunchOptionsURLKey] ?: @"",
#endif
}];
#elif TARGET_OS_OSX
[self track:@"Application Opened" properties:@{
Expand Down
8 changes: 6 additions & 2 deletions Segment/Classes/SEGAnalyticsConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

@import Foundation;

#if TARGET_OS_IPHONE
#if TARGET_OS_WATCH
@import WatchKit;
#elif TARGET_OS_IPHONE
@import UIKit;
#elif TARGET_OS_OSX
@import Cocoa;
Expand All @@ -17,7 +19,9 @@
NS_SWIFT_NAME(ApplicationProtocol)
@protocol SEGApplicationProtocol <NSObject>

#if TARGET_OS_IPHONE
#if TARGET_OS_WATCH
@property (nullable, nonatomic, assign) id<WKApplicationDelegate> delegate;
#elif TARGET_OS_IPHONE
@property (nullable, nonatomic, assign) id<UIApplicationDelegate> delegate;
#elif TARGET_OS_OSX
@property (nullable, nonatomic, assign) id<NSApplicationDelegate> delegate;
Expand Down
8 changes: 6 additions & 2 deletions Segment/Classes/SEGAnalyticsConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
@import Cocoa;
#endif

#if TARGET_OS_IPHONE
#if TARGET_OS_IPHONE && !TARGET_OS_WATCH
@implementation UIApplication (SEGApplicationProtocol)

- (UIBackgroundTaskIdentifier)seg_beginBackgroundTaskWithName:(nullable NSString *)taskName expirationHandler:(void (^__nullable)(void))handler
Expand Down Expand Up @@ -96,7 +96,11 @@ - (instancetype)init
@"(fb\\d+://authorize#access_token=)([^ ]+)": @"$1((redacted/fb-auth-token))"
};
_factories = [NSMutableArray array];
#if TARGET_OS_IPHONE
#if TARGET_OS_WATCH
if ([WKApplication respondsToSelector:@selector(sharedApplication)]){
_application = [WKApplication performSelector:@selector(sharedApplication)];
}
#elif TARGET_OS_IPHONE
if ([UIApplication respondsToSelector:@selector(sharedApplication)]) {
_application = [UIApplication performSelector:@selector(sharedApplication)];
}
Expand Down
4 changes: 4 additions & 0 deletions Segment/Classes/SEGReachability.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#import <TargetConditionals.h>

#if !TARGET_OS_WATCH
/*
Copyright (c) 2011, Tony Million.
All rights reserved.
Expand Down Expand Up @@ -103,3 +106,4 @@ NS_SWIFT_NAME(Reachability)
@end

NS_ASSUME_NONNULL_END
#endif
3 changes: 2 additions & 1 deletion Segment/Classes/SEGReachability.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#import <netdb.h>
#import "SEGReachability.h"


#if !TARGET_OS_WATCH
NSString *const kSEGReachabilityChangedNotification = @"kSEGReachabilityChangedNotification";


Expand Down Expand Up @@ -497,3 +497,4 @@ - (NSString *) description
}

@end
#endif
2 changes: 1 addition & 1 deletion Segment/Classes/SEGScreenReporting.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN

@protocol SEGScreenReporting
@optional
#if TARGET_OS_IPHONE
#if TARGET_OS_IPHONE && !TARGET_OS_WATCH
- (void)seg_trackScreen:(UIViewController*)screen name:(NSString*)name;
@property (readonly, nullable) UIViewController *seg_mainViewController;
#elif TARGET_OS_OSX
Expand Down
8 changes: 6 additions & 2 deletions Segment/Classes/SEGSegmentIntegration.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ @interface SEGSegmentIntegration ()

@property (nonatomic, strong) NSMutableArray *queue;
@property (nonatomic, strong) NSURLSessionUploadTask *batchRequest;
#if !TARGET_OS_WATCH
@property (nonatomic, strong) SEGReachability *reachability;
#endif
@property (nonatomic, strong) NSTimer *flushTimer;
@property (nonatomic, strong) dispatch_queue_t serialQueue;
@property (nonatomic, strong) dispatch_queue_t backgroundTaskQueue;
Expand All @@ -47,7 +49,7 @@ @interface SEGSegmentIntegration ()
@property (nonatomic, strong) id<SEGStorage> fileStorage;
@property (nonatomic, strong) id<SEGStorage> userDefaultsStorage;

#if TARGET_OS_IPHONE
#if TARGET_OS_IPHONE && !TARGET_OS_WATCH
@property (nonatomic, assign) UIBackgroundTaskIdentifier flushTaskID;
#else
@property (nonatomic, assign) NSUInteger flushTaskID;
Expand All @@ -70,11 +72,13 @@ - (id)initWithAnalytics:(SEGAnalytics *)analytics httpClient:(SEGHTTPClient *)ht
self.httpClient.httpSessionDelegate = analytics.oneTimeConfiguration.httpSessionDelegate;
self.fileStorage = fileStorage;
self.userDefaultsStorage = userDefaultsStorage;
#if !TARGET_OS_WATCH
self.reachability = [SEGReachability reachabilityWithHostname:@"google.com"];
[self.reachability startNotifier];
#endif
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
#if TARGET_OS_IPHONE && !TARGET_OS_WATCH
self.flushTaskID = UIBackgroundTaskInvalid;
#else
self.flushTaskID = 0; // the actual value of UIBackgroundTaskInvalid
Expand Down
17 changes: 15 additions & 2 deletions Segment/Internal/SEGIntegrationsManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ - (instancetype _Nonnull)initWithAnalytics:(SEGAnalytics *_Nonnull)analytics
if (application) {
// Attach to application state change hooks
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
#if TARGET_OS_IPHONE
#if TARGET_OS_IPHONE && !TARGET_OS_WATCH
[nc addObserver:self selector:@selector(onAppForeground:) name:UIApplicationWillEnterForegroundNotification object:application];
#elif TARGET_OS_OSX
[nc addObserver:self selector:@selector(onAppForeground:) name:NSApplicationWillBecomeActiveNotification object:application];
Expand Down Expand Up @@ -167,7 +167,20 @@ - (void)handleAppStateNotification:(NSString *)notificationName
static NSDictionary *selectorMapping;
static dispatch_once_t selectorMappingOnce;
dispatch_once(&selectorMappingOnce, ^{
#if TARGET_OS_IPHONE
#if TARGET_OS_WATCH
selectorMapping = @{
WKApplicationDidFinishLaunchingNotification :
NSStringFromSelector(@selector(applicationDidFinishLaunching:)),
WKApplicationDidEnterBackgroundNotification :
NSStringFromSelector(@selector(applicationDidEnterBackground)),
WKApplicationWillEnterForegroundNotification :
NSStringFromSelector(@selector(applicationWillEnterForeground)),
WKApplicationWillResignActiveNotification :
NSStringFromSelector(@selector(applicationWillResignActive)),
WKApplicationDidBecomeActiveNotification :
NSStringFromSelector(@selector(applicationDidBecomeActive))
};
#elif TARGET_OS_IPHONE

selectorMapping = @{
UIApplicationDidFinishLaunchingNotification :
Expand Down
4 changes: 4 additions & 0 deletions Segment/Internal/SEGState.m
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ - (void)setTraits:(NSDictionary *)traits
@implementation SEGPayloadContext

@synthesize state;
#if !TARGET_OS_WATCH
@synthesize reachability;
#endif

@synthesize referrer = _referrer;
@synthesize cachedStaticContext = _cachedStaticContext;
Expand All @@ -118,8 +120,10 @@ - (instancetype)initWithState:(SEGState *)aState
{
if (self = [super init]) {
self.state = aState;
#if !TARGET_OS_WATCH
self.reachability = [SEGReachability reachabilityWithHostname:@"google.com"];
[self.reachability startNotifier];
#endif
}
return self;
}
Expand Down
4 changes: 3 additions & 1 deletion Segment/Internal/SEGUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ NSDictionary *getLiveContext(SEGReachability *reachability, NSDictionary * _Null

NSString *GenerateUUIDString(void);

#if TARGET_OS_IPHONE
#if TARGET_OS_WATCH
NSDictionary *watchSpecifications(SEGAnalyticsConfiguration *configuration, NSString * _Nullable deviceToken);
#elif TARGET_OS_IPHONE
NSDictionary *mobileSpecifications(SEGAnalyticsConfiguration *configuration, NSString * _Nullable deviceToken);
#elif TARGET_OS_OSX
NSDictionary *desktopSpecifications(SEGAnalyticsConfiguration *configuration, NSString * _Nullable deviceToken);
Expand Down
50 changes: 48 additions & 2 deletions Segment/Internal/SEGUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,9 @@ BOOL getAdTrackingEnabled(SEGAnalyticsConfiguration *configuration)
}

NSDictionary *settingsDictionary = nil;
#if TARGET_OS_IPHONE
#if TARGET_OS_WATCH
settingsDictionary = watchSpecifications(configuration, deviceToken);
#elif TARGET_OS_IPHONE
settingsDictionary = mobileSpecifications(configuration, deviceToken);
#elif TARGET_OS_OSX
settingsDictionary = desktopSpecifications(configuration, deviceToken);
Expand All @@ -216,7 +218,49 @@ BOOL getAdTrackingEnabled(SEGAnalyticsConfiguration *configuration)
return dict;
}

#if TARGET_OS_IPHONE
#if TARGET_OS_WATCH
NSDictionary *watchSpecifications(SEGAnalyticsConfiguration *configuration, NSString *deviceToken)
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
WKInterfaceDevice *device = [WKInterfaceDevice currentDevice];
dict[@"device"] = ({
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
dict[@"manufacturer"] = @"Apple";
dict[@"type"] = @"watchos";
dict[@"name"] = [device model];
dict[@"model"] = getDeviceModel();
dict[@"id"] = [[device identifierForVendor] UUIDString];
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);

if (adTrackingEnabled) {
dict[@"advertisingId"] = idfa;
}
}
if (deviceToken && deviceToken.length > 0) {
dict[@"token"] = deviceToken;
}
dict;
});

dict[@"os"] = @{
@"name" : device.systemName,
@"version" : device.systemVersion
};

CGSize screenSize = device.screenBounds.size;
dict[@"screen"] = @{
@"width" : @(screenSize.width),
@"height" : @(screenSize.height)
};

return dict;
}
#elif TARGET_OS_IPHONE
NSDictionary *mobileSpecifications(SEGAnalyticsConfiguration *configuration, NSString *deviceToken)
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
Expand Down Expand Up @@ -360,10 +404,12 @@ BOOL getAdTrackingEnabled(SEGAnalyticsConfiguration *configuration)
context[@"network"] = ({
NSMutableDictionary *network = [[NSMutableDictionary alloc] init];

#if !TARGET_OS_WATCH
if (reachability.isReachable) {
network[@"wifi"] = @(reachability.isReachableViaWiFi);
network[@"cellular"] = @(reachability.isReachableViaWWAN);
}
#endif

#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
static dispatch_once_t networkInfoOnceToken;
Expand Down
2 changes: 1 addition & 1 deletion Segment/Internal/UIViewController+SEGScreen.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#import "SEGSerializableValue.h"

#if TARGET_OS_IPHONE
#if TARGET_OS_IPHONE && !TARGET_OS_WATCH
@import UIKit;

@interface UIViewController (SEGScreen)
Expand Down
2 changes: 1 addition & 1 deletion Segment/Internal/UIViewController+SEGScreen.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#import "SEGScreenReporting.h"


#if TARGET_OS_IPHONE
#if TARGET_OS_IPHONE && !TARGET_OS_WATCH
@implementation UIViewController (SEGScreen)

+ (void)seg_swizzleViewDidAppear
Expand Down