Skip to content

Commit

Permalink
Add tvOS Support (#572)
Browse files Browse the repository at this point in the history
  • Loading branch information
f2prateek authored Jul 1, 2016
1 parent b28726a commit d7926d4
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
language: objective-c

osx_image: xcode7
osx_image: xcode7.3

before_install:
- make bootstrap
Expand Down
1 change: 1 addition & 0 deletions Analytics.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Pod::Spec.new do |s|
s.social_media_url = 'https://twitter.com/segment'

s.ios.deployment_target = '7.0'
s.tvos.deployment_target = '9.0'

s.source_files = 'Analytics/Classes/**/*'
end
3 changes: 3 additions & 0 deletions Analytics/Classes/Internal/SEGAnalyticsRequest.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ - (id)initWithURLRequest:(NSURLRequest *)urlRequest

- (void)start
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
self.connection = [[NSURLConnection alloc] initWithRequest:self.urlRequest
delegate:self
startImmediately:NO];
#pragma clang diagnostic pop
[self.connection setDelegateQueue:[[self class] networkQueue]];
[self.connection start];
}
Expand Down
3 changes: 3 additions & 0 deletions Analytics/Classes/Internal/SEGLocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
@property (nonatomic, copy, readonly) NSDictionary *addressDictionary;
@property (nonatomic, assign, readonly) BOOL hasKnownLocation;


#if TARGET_OS_IOS || (TARGET_OS_MAC && !TARGET_OS_IPHONE)
- (void)startUpdatingLocation;
#endif

@end
6 changes: 6 additions & 0 deletions Analytics/Classes/Internal/SEGLocation.m
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ - (id)init
dispatch_async(dispatch_get_main_queue(), ^{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
#if TARGET_OS_IOS
[self.locationManager startUpdatingLocation];
#endif
});
}
return self;
Expand All @@ -60,10 +62,13 @@ - (id)init
LOCATION_STRING_PROPERTY(street, thoroughfare);
LOCATION_NUMBER_PROPERTY(latitude, location.coordinate.latitude);
LOCATION_NUMBER_PROPERTY(longitude, location.coordinate.longitude);

#if TARGET_OS_IOS || (TARGET_OS_MAC && !TARGET_OS_IPHONE)
LOCATION_NUMBER_PROPERTY(speed, location.speed);

- (void)startUpdatingLocation
{

if (self.locationManager && self.currentPlacemark) {
CLLocation *location = self.currentPlacemark.location;
NSDate *eventDate = location.timestamp;
Expand All @@ -75,6 +80,7 @@ - (void)startUpdatingLocation
}
}
}
#endif

- (BOOL)hasKnownLocation
{
Expand Down
86 changes: 76 additions & 10 deletions Analytics/Classes/Internal/SEGSegmentIntegration.m
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#include <sys/sysctl.h>

#import <UIKit/UIKit.h>
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import "SEGAnalytics.h"
#import "SEGAnalyticsUtils.h"
#import "SEGAnalyticsRequest.h"
Expand All @@ -11,7 +9,11 @@
#import "SEGReachability.h"
#import "SEGLocation.h"
#import "NSData+GZIP.h"
#import <iAd/iAd.h>

#if TARGET_OS_IOS
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#endif

NSString *const SEGSegmentDidSendRequestNotification = @"SegmentDidSendRequest";
NSString *const SEGSegmentRequestDidSucceedNotification = @"SegmentRequestDidSucceed";
Expand Down Expand Up @@ -90,6 +92,8 @@ - (id)initWithAnalytics:(SEGAnalytics *)analytics
self.serialQueue = seg_dispatch_queue_create_specific("io.segment.analytics.segmentio", DISPATCH_QUEUE_SERIAL);
self.flushTaskID = UIBackgroundTaskInvalid;
self.analytics = analytics;

#if !TARGET_OS_TV
// Check for previous queue/track data in NSUserDefaults and remove if present
[self dispatchBackground:^{
if ([[NSUserDefaults standardUserDefaults] objectForKey:SEGQueueKey]) {
Expand All @@ -99,13 +103,17 @@ - (id)initWithAnalytics:(SEGAnalytics *)analytics
[[NSUserDefaults standardUserDefaults] removeObjectForKey:SEGTraitsKey];
}
}];
dispatch_sync(dispatch_get_main_queue(), ^{
self.flushTimer = [NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(flush) userInfo:nil repeats:YES];
});


[self addSkipBackupAttributeToItemAtPath:self.userIDURL];
[self addSkipBackupAttributeToItemAtPath:self.anonymousIDURL];
[self addSkipBackupAttributeToItemAtPath:self.traitsURL];
[self addSkipBackupAttributeToItemAtPath:self.queueURL];
#endif

dispatch_sync(dispatch_get_main_queue(), ^{
self.flushTimer = [NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(flush) userInfo:nil repeats:YES];
});
}
return self;
}
Expand All @@ -119,7 +127,9 @@ - (id)initWithAnalytics:(SEGAnalytics *)analytics
* Ref: http://stackoverflow.com/questions/14238586/coretelephony-crash
*/

#if TARGET_OS_IOS
static CTTelephonyNetworkInfo *_telephonyNetworkInfo;
#endif

- (NSDictionary *)staticContext
{
Expand Down Expand Up @@ -163,6 +173,7 @@ - (NSDictionary *)staticContext
@"version" : device.systemVersion
};

#if TARGET_OS_IOS
static dispatch_once_t networkInfoOnceToken;
dispatch_once(&networkInfoOnceToken, ^{
_telephonyNetworkInfo = [[CTTelephonyNetworkInfo alloc] init];
Expand All @@ -171,6 +182,7 @@ - (NSDictionary *)staticContext
CTCarrier *carrier = [_telephonyNetworkInfo subscriberCellularProvider];
if (carrier.carrierName.length)
dict[@"network"] = @{ @"carrier" : carrier.carrierName };
#endif

CGSize screenSize = [UIScreen mainScreen].bounds.size;
dict[@"screen"] = @{
Expand Down Expand Up @@ -229,7 +241,11 @@ - (NSDictionary *)liveContext
});

self.location = !self.location ? [self.configuration shouldUseLocationServices] ? [SEGLocation new] : nil : self.location;

#if TARGET_OS_IOS || (TARGET_OS_MAC && !TARGET_OS_IPHONE)
[self.location startUpdatingLocation];
#endif

if (self.location.hasKnownLocation)
context[@"location"] = self.location.locationDictionary;

Expand Down Expand Up @@ -283,24 +299,37 @@ - (void)saveUserId:(NSString *)userId
{
[self dispatchBackground:^{
self.userId = userId;

#if TARGET_OS_TV
[[NSUserDefaults standardUserDefaults] setValue:userId forKey:SEGUserIdKey];
#else
[self.userId writeToURL:self.userIDURL atomically:YES encoding:NSUTF8StringEncoding error:NULL];
#endif
}];
}

- (void)saveAnonymousId:(NSString *)anonymousId
{
[self dispatchBackground:^{
self.anonymousId = anonymousId;
#if TARGET_OS_TV
[[NSUserDefaults standardUserDefaults] setValue:anonymousId forKey:SEGAnonymousIdKey];
#else
[self.anonymousId writeToURL:self.anonymousIDURL atomically:YES encoding:NSUTF8StringEncoding error:NULL];
#endif
}];
}

- (void)addTraits:(NSDictionary *)traits
{
[self dispatchBackground:^{
[self.traits addEntriesFromDictionary:traits];

#if TARGET_OS_TV
[[NSUserDefaults standardUserDefaults] setValue:[self.traits copy] forKey:SEGTraitsKey];
#else
[[self.traits copy] writeToURL:self.traitsURL atomically:YES];
#endif
}];
}

Expand Down Expand Up @@ -425,7 +454,7 @@ - (void)queuePayload:(NSDictionary *)payload
[self.queue removeObjectAtIndex:0];
}
[self.queue addObject:payload];
[[self.queue copy] writeToURL:[self queueURL] atomically:YES];
[self persistQueue];
[self flushQueueByLength];
}
@catch (NSException *exception) {
Expand Down Expand Up @@ -496,9 +525,16 @@ - (void)reset
[self dispatchBackgroundAndWait:^{
[[NSUserDefaults standardUserDefaults] setValue:nil forKey:SEGUserIdKey];
[[NSUserDefaults standardUserDefaults] setValue:nil forKey:SEGAnonymousIdKey];

#if TARGET_OS_TV
[[NSUserDefaults standardUserDefaults] setValue:@[] forKey:SEGQueueKey];
[[NSUserDefaults standardUserDefaults] setValue:@{} forKey:SEGTraitsKey];
#else
[[NSFileManager defaultManager] removeItemAtURL:self.userIDURL error:NULL];
[[NSFileManager defaultManager] removeItemAtURL:self.traitsURL error:NULL];
[[NSFileManager defaultManager] removeItemAtURL:self.queueURL error:NULL];
#endif

self.userId = nil;
self.traits = [NSMutableDictionary dictionary];
self.queue = [NSMutableArray array];
Expand Down Expand Up @@ -553,7 +589,7 @@ - (void)sendData:(NSData *)data
} else {
SEGLog(@"%@ API request success 200", self);
[self.queue removeObjectsInArray:self.batch];
[[self.queue copy] writeToURL:[self queueURL] atomically:YES];
[self persistQueue];
[self notifyForName:SEGSegmentRequestDidSucceedNotification userInfo:self.batch];
}

Expand All @@ -577,7 +613,7 @@ - (void)applicationWillTerminate
{
[self dispatchBackgroundAndWait:^{
if (self.queue.count)
[[self.queue copy] writeToURL:self.queueURL atomically:YES];
[self persistQueue];
}];
}

Expand All @@ -586,16 +622,26 @@ - (void)applicationWillTerminate
- (NSMutableArray *)queue
{
if (!_queue) {
#if TARGET_OS_TV
_queue = [[[NSUserDefaults standardUserDefaults] objectForKey:SEGQueueKey] mutableCopy] ?: [[NSMutableArray alloc] init];
#else
_queue = [NSMutableArray arrayWithContentsOfURL:self.queueURL] ?: [[NSMutableArray alloc] init];
#endif
}

return _queue;
}

- (NSMutableDictionary *)traits
{
if (!_traits) {
#if TARGET_OS_TV
_traits = [[[NSUserDefaults standardUserDefaults] objectForKey:SEGTraitsKey] mutableCopy] ?: [[NSMutableDictionary alloc] init];
#else
_traits = [NSMutableDictionary dictionaryWithContentsOfURL:self.traitsURL] ?: [[NSMutableDictionary alloc] init];
#endif
}

return _traits;
}

Expand Down Expand Up @@ -629,14 +675,25 @@ - (NSString *)getAnonymousId:(BOOL)reset
// We've chosen to generate a UUID rather than use the UDID (deprecated in iOS 5),
// identifierForVendor (iOS6 and later, can't be changed on logout),
// or MAC address (blocked in iOS 7). For more info see https://segment.io/libraries/ios#ids

#if TARGET_OS_TV
NSString *anonymousId = [[NSUserDefaults standardUserDefaults] valueForKey:SEGAnonymousIdKey];
#else
NSURL *url = self.anonymousIDURL;
NSString *anonymousId = [[NSUserDefaults standardUserDefaults] valueForKey:SEGAnonymousIdKey] ?: [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:NULL];
NSString *anonymousId = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:NULL];
#endif

if (!anonymousId || reset) {
anonymousId = GenerateUUIDString();
SEGLog(@"New anonymousId: %@", anonymousId);

#if TARGET_OS_TV
[[NSUserDefaults standardUserDefaults] setObject:anonymousId forKey:SEGAnonymousIdKey];
#else
[anonymousId writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:NULL];
#endif
}

return anonymousId;
}

Expand All @@ -645,4 +702,13 @@ - (NSString *)getUserId
return [[NSUserDefaults standardUserDefaults] valueForKey:SEGUserIdKey] ?: [[NSString alloc] initWithContentsOfURL:self.userIDURL encoding:NSUTF8StringEncoding error:NULL];
}

- (void)persistQueue
{
#if TARGET_OS_TV
[[NSUserDefaults standardUserDefaults] setValue:[self.queue copy] forKey:SEGQueueKey];
#else
[[self.queue copy] writeToURL:[self queueURL] atomically:YES];
#endif
}

@end
4 changes: 4 additions & 0 deletions Analytics/Classes/SEGAnalytics.m
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,17 @@ - (instancetype)initWithConfiguration:(SEGAnalyticsConfiguration *)configuration
if (configuration.trackInAppPurchases) {
_storeKitTracker = [SEGStoreKitTracker trackTransactionsForAnalytics:self];
}

[self trackApplicationLifecycleEvents:configuration.trackApplicationLifecycleEvents];

#if !TARGET_OS_TV
if (configuration.trackPushNotifications && configuration.launchOptions) {
NSDictionary *remoteNotification = configuration.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteNotification) {
[self trackPushNotification:remoteNotification fromLaunch:YES];
}
}
#endif
}
return self;
}
Expand Down
4 changes: 2 additions & 2 deletions Example/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PODS:
- Analytics (3.2.4)
- Analytics (3.2.5)
- Expecta (1.0.5)
- Specta (1.0.5)

Expand All @@ -13,7 +13,7 @@ EXTERNAL SOURCES:
:path: ../

SPEC CHECKSUMS:
Analytics: 7db6a16e81dc98c500337846f8351de7e9067699
Analytics: 9ff192fcc0ca6d2999822b8883b05c57362bbd8f
Expecta: e1c022fcd33910b6be89c291d2775b3fe27a89fe
Specta: ac94d110b865115fe60ff2c6d7281053c6f8e8a2

Expand Down
7 changes: 4 additions & 3 deletions Example/Pods/Local Podspecs/Analytics.podspec.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Example/Pods/Manifest.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Example/Pods/Target Support Files/Analytics/Info.plist

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d7926d4

Please sign in to comment.