Skip to content

Commit

Permalink
Misc Fixes (#884)
Browse files Browse the repository at this point in the history
* Add name and properties to auto screen reporting

* Make seg_topViewController handle tab and custom container VCs

* Simplify SEGScreenReporting protocol

Inspired by comments from @f2prateek, simplify the the `SEGScreenReporting` protocol to replace the name and properties fields with a single method (`seg_trackScreen`) that can be implemented when screen tracking for a specific view controller that needs a custom name, properties, or options.

* Update Nimble to build with Xcode 10.2

* Add tests for seg_topViewController

* fixed a crash in file storage when trying to get a string stored using old SDK version (#880)

* Fixed issue where build/version were removed from Application Opened events from background state.

* Publish filenames used for data storage (#865)

* Remove tvos test from scheme setup.

* Fixed selector reference.

* Removed unused code.

Co-authored-by: David Whetstone <[email protected]>
Co-authored-by: Sergei Guselnikov <[email protected]>
Co-authored-by: Brandon Sneed <[email protected]>
Co-authored-by: Błażej Biesiada <[email protected]>
  • Loading branch information
5 people authored May 12, 2020
1 parent df608de commit ff5d309
Show file tree
Hide file tree
Showing 19 changed files with 272 additions and 37 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ Carthage
# itself has no pod dependencies, only our tests do.
Pods/
.clang-format
.idea
12 changes: 12 additions & 0 deletions Analytics.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

/* Begin PBXBuildFile section */
067E6A3191007B3442DB29F0 /* Pods_AnalyticsTestsTVOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66058A0DB75544E7C2766C31 /* Pods_AnalyticsTestsTVOS.framework */; };
5AF0E8AE77F57B356DACCFE7 /* AutoScreenReportingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AF0E8457CCFC077382BF449 /* AutoScreenReportingTest.swift */; };
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 */; };
9D8CE59023EE014E00197D0C /* CryptoTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADEB8E91DECD335005322DA /* CryptoTest.swift */; };
Expand All @@ -27,6 +29,7 @@
9D8CE59E23EE014E00197D0C /* TestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADEB8E41DECD335005322DA /* TestUtils.swift */; };
9D8CE5A023EE014E00197D0C /* Analytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EADEB85B1DECD080005322DA /* Analytics.framework */; };
A31958EF2385AC3A00A47EFA /* SerializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A31958EE2385AC3A00A47EFA /* SerializationTests.m */; };
A31CAFC224635F8400443BA4 /* AutoScreenReportingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AF0E8457CCFC077382BF449 /* AutoScreenReportingTest.swift */; };
A352176023AD5825005B07F6 /* SEGMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = A352175F23AD5825005B07F6 /* SEGMacros.h */; settings = {ATTRIBUTES = (Private, ); }; };
E4ACAD51DB827114D8626C74 /* Pods_AnalyticsTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5238C0454BF56A36A536C5C1 /* Pods_AnalyticsTests.framework */; };
EA88A5981DED7608009FB66A /* SEGSerializableValue.h in Headers */ = {isa = PBXBuildFile; fileRef = EA88A5971DED7608009FB66A /* SEGSerializableValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -117,6 +120,9 @@
03630CF57D6F100AC46A95FD /* Pods-AnalyticsTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AnalyticsTests.release.xcconfig"; path = "Target Support Files/Pods-AnalyticsTests/Pods-AnalyticsTests.release.xcconfig"; sourceTree = "<group>"; };
4E5B177C4F6C1CAE4837FF7B /* Pods-AnalyticsTestsTVOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AnalyticsTestsTVOS.debug.xcconfig"; path = "Target Support Files/Pods-AnalyticsTestsTVOS/Pods-AnalyticsTestsTVOS.debug.xcconfig"; sourceTree = "<group>"; };
5238C0454BF56A36A536C5C1 /* Pods_AnalyticsTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AnalyticsTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5AF0E8457CCFC077382BF449 /* AutoScreenReportingTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoScreenReportingTest.swift; sourceTree = "<group>"; };
5AF0EDFEDC0EE79A0A0EB713 /* SEGScreenReporting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SEGScreenReporting.h; sourceTree = "<group>"; };
63E090D722DD49C300DEC7EC /* UIViewController+SegScreenTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIViewController+SegScreenTest.h"; sourceTree = "<group>"; };
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 = "<group>"; };
6EEC1C702017EA370089C478 /* EndToEndTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndToEndTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -312,6 +318,8 @@
6E265C781FB1178C0030E08E /* IntegrationsManagerTest.swift */,
6EEC1C702017EA370089C478 /* EndToEndTests.swift */,
A31958EE2385AC3A00A47EFA /* SerializationTests.m */,
5AF0E8457CCFC077382BF449 /* AutoScreenReportingTest.swift */,
63E090D722DD49C300DEC7EC /* UIViewController+SegScreenTest.h */,
);
indentWidth = 2;
path = AnalyticsTests;
Expand Down Expand Up @@ -393,6 +401,7 @@
A352175F23AD5825005B07F6 /* SEGMacros.h */,
EADEB8A21DECD12B005322DA /* UIViewController+SEGScreen.h */,
EADEB8A31DECD12B005322DA /* UIViewController+SEGScreen.m */,
5AF0EDFEDC0EE79A0A0EB713 /* SEGScreenReporting.h */,
);
path = Internal;
sourceTree = "<group>";
Expand Down Expand Up @@ -461,6 +470,7 @@
EADEB8601DECD080005322DA /* Analytics.h in Headers */,
EADEB8C31DECD12B005322DA /* SEGAnalyticsUtils.h in Headers */,
EADEB8B91DECD12B005322DA /* SEGIntegrationsManager.h in Headers */,
630FC8EA2107F2A500A759C5 /* SEGScreenReporting.h in Headers */,
EADEB8AE1DECD12B005322DA /* SEGAES256Crypto.h in Headers */,
EADEB8C51DECD12B005322DA /* SEGFileStorage.h in Headers */,
EAA5427D1EB42B8C00945DA7 /* SEGReachability.h in Headers */,
Expand Down Expand Up @@ -712,6 +722,7 @@
9D8CE59823EE014E00197D0C /* AnalyticsUtilTests.swift in Sources */,
9D8CE59923EE014E00197D0C /* StoreKitTrackerTests.swift in Sources */,
9D8CE59A23EE014E00197D0C /* MiddlewareTests.swift in Sources */,
A31CAFC224635F8400443BA4 /* AutoScreenReportingTest.swift in Sources */,
9D8CE59B23EE014E00197D0C /* IntegrationsManagerTest.swift in Sources */,
9D8CE59C23EE014E00197D0C /* NSData+SEGGUNZIPP.m in Sources */,
9D8CE59D23EE014E00197D0C /* EndToEndTests.swift in Sources */,
Expand Down Expand Up @@ -768,6 +779,7 @@
EADEB8EF1DECD335005322DA /* NSData+SEGGUNZIPP.m in Sources */,
6EEC1C712017EA370089C478 /* EndToEndTests.swift in Sources */,
EADEB8F01DECD335005322DA /* TestUtils.swift in Sources */,
5AF0E8AE77F57B356DACCFE7 /* AutoScreenReportingTest.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
14 changes: 0 additions & 14 deletions Analytics.xcodeproj/xcshareddata/xcschemes/Analytics.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,6 @@
ReferencedContainer = "container:Analytics.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "NO"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9D8CE58B23EE014E00197D0C"
BuildableName = "AnalyticsTestsTVOS.xctest"
BlueprintName = "AnalyticsTestsTVOS"
ReferencedContainer = "container:Analytics.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
Expand Down
1 change: 1 addition & 0 deletions Analytics/Analytics.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ FOUNDATION_EXPORT const unsigned char AnalyticsVersionString[];
#import "SEGSegmentIntegrationFactory.h"
#import "SEGContext.h"
#import "SEGMiddleware.h"
#import "SEGScreenReporting.h"
6 changes: 6 additions & 0 deletions Analytics/Classes/Integrations/SEGIntegrationsManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
#import <Foundation/Foundation.h>
#import "SEGMiddleware.h"

/**
* Filenames of "Application Support" files where essential data is stored.
*/
extern NSString *_Nonnull const kSEGAnonymousIdFilename;
extern NSString *_Nonnull const kSEGCachedSettingsFilename;

/**
* NSNotification name, that is posted after integrations are loaded.
*/
Expand Down
14 changes: 7 additions & 7 deletions Analytics/Classes/Integrations/SEGIntegrationsManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
#import "SEGAliasPayload.h"

NSString *SEGAnalyticsIntegrationDidStart = @"io.segment.analytics.integration.did.start";
static NSString *const SEGAnonymousIdKey = @"SEGAnonymousId";
static NSString *const kSEGAnonymousIdFilename = @"segment.anonymousId";
static NSString *const SEGCachedSettingsKey = @"analytics.settings.v2.plist";
NSString *const SEGAnonymousIdKey = @"SEGAnonymousId";
NSString *const kSEGAnonymousIdFilename = @"segment.anonymousId";
NSString *const kSEGCachedSettingsFilename = @"analytics.settings.v2.plist";


@interface SEGIdentifyPayload (AnonymousId)
Expand Down Expand Up @@ -357,9 +357,9 @@ - (NSDictionary *)cachedSettings
{
if (!_cachedSettings) {
#if TARGET_OS_TV
_cachedSettings = [self.userDefaultsStorage dictionaryForKey:SEGCachedSettingsKey] ?: @{};
_cachedSettings = [self.userDefaultsStorage dictionaryForKey:kSEGCachedSettingsFilename] ?: @{};
#else
_cachedSettings = [self.fileStorage dictionaryForKey:SEGCachedSettingsKey] ?: @{};
_cachedSettings = [self.fileStorage dictionaryForKey:kSEGCachedSettingsFilename] ?: @{};
#endif
}

Expand All @@ -375,9 +375,9 @@ - (void)setCachedSettings:(NSDictionary *)settings
}

#if TARGET_OS_TV
[self.userDefaultsStorage setDictionary:_cachedSettings forKey:SEGCachedSettingsKey];
[self.userDefaultsStorage setDictionary:_cachedSettings forKey:kSEGCachedSettingsFilename];
#else
[self.fileStorage setDictionary:_cachedSettings forKey:SEGCachedSettingsKey];
[self.fileStorage setDictionary:_cachedSettings forKey:kSEGCachedSettingsFilename];
#endif

[self updateIntegrationsWithSettings:settings[@"integrations"]];
Expand Down
3 changes: 0 additions & 3 deletions Analytics/Classes/Internal/SEGAnalyticsUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ NS_ASSUME_NONNULL_BEGIN

NSString *GenerateUUIDString(void);

// Validation Utils
BOOL serializableDictionaryTypes(NSDictionary *dict);

// Date Utils
NSString *iso8601FormattedString(NSDate *date);
NSString *iso8601NanoFormattedString(NSDate *date);
Expand Down
12 changes: 10 additions & 2 deletions Analytics/Classes/Internal/SEGFileStorage.m
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,18 @@ - (void)setArray:(nullable NSArray *)array forKey:(NSString *)key

- (nullable NSString *)stringForKey:(NSString *)key
{
NSDictionary *data = [self jsonForKey:key];
if (data) {
id data = [self jsonForKey:key];

if (data == nil) {
return nil;
}

if ([data isKindOfClass:[NSString class]]) {
return data;
} else if ([data isKindOfClass:[NSDictionary class]]) {
return data[key];
}

return nil;
}

Expand Down
17 changes: 17 additions & 0 deletions Analytics/Classes/Internal/SEGScreenReporting.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#import <UIKit/UIKit.h>
#import "SEGSerializableValue.h"

/** Implement this protocol to override automatic screen reporting
*/

NS_ASSUME_NONNULL_BEGIN

@protocol SEGScreenReporting
@optional
-(void) seg_trackScreen:(UIViewController*)screen name:(NSString*)name;
@property (readonly, nullable) UIViewController *seg_mainViewController;
@end

NS_ASSUME_NONNULL_END


7 changes: 7 additions & 0 deletions Analytics/Classes/Internal/SEGSegmentIntegration.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ extern NSString *const SEGSegmentDidSendRequestNotification;
extern NSString *const SEGSegmentRequestDidSucceedNotification;
extern NSString *const SEGSegmentRequestDidFailNotification;

/**
* Filenames of "Application Support" files where essential data is stored.
*/
extern NSString *const kSEGUserIdFilename;
extern NSString *const kSEGQueueFilename;
extern NSString *const kSEGTraitsFilename;


@interface SEGSegmentIntegration : NSObject <SEGIntegration>

Expand Down
3 changes: 2 additions & 1 deletion Analytics/Classes/Internal/UIViewController+SEGScreen.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#import <UIKit/UIKit.h>

#import "SEGSerializableValue.h"

@interface UIViewController (SEGScreen)

+ (void)seg_swizzleViewDidAppear;
+ (UIViewController *)seg_topViewController;

@end

46 changes: 42 additions & 4 deletions Analytics/Classes/Internal/UIViewController+SEGScreen.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#import <objc/runtime.h>
#import "SEGAnalytics.h"
#import "SEGAnalyticsUtils.h"
#import "SEGScreenReporting.h"


@implementation UIViewController (SEGScreen)
Expand Down Expand Up @@ -43,18 +44,48 @@ + (UIViewController *)seg_topViewController
}

+ (UIViewController *)seg_topViewController:(UIViewController *)rootViewController
{
UIViewController *nextRootViewController = [self seg_nextRootViewController:rootViewController];
if (nextRootViewController) {
return [self seg_topViewController:nextRootViewController];
}

return rootViewController;
}

+ (UIViewController *)seg_nextRootViewController:(UIViewController *)rootViewController
{
UIViewController *presentedViewController = rootViewController.presentedViewController;
if (presentedViewController != nil) {
return [self seg_topViewController:presentedViewController];
return presentedViewController;
}

if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UIViewController *lastViewController = [[(UINavigationController *)rootViewController viewControllers] lastObject];
return [self seg_topViewController:lastViewController];
UIViewController *lastViewController = ((UINavigationController *)rootViewController).viewControllers.lastObject;
return lastViewController;
}

return rootViewController;
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
__auto_type *currentTabViewController = ((UITabBarController*)rootViewController).selectedViewController;
if (currentTabViewController != nil) {
return currentTabViewController;
}
}

if (rootViewController.childViewControllers.count > 0) {
if ([rootViewController conformsToProtocol:@protocol(SEGScreenReporting)] && [rootViewController respondsToSelector:@selector(seg_mainViewController)]) {
__auto_type screenReporting = (UIViewController<SEGScreenReporting>*)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 nil;
}

- (void)seg_viewDidAppear:(BOOL)animated
Expand All @@ -74,6 +105,13 @@ - (void)seg_viewDidAppear:(BOOL)animated
name = @"Unknown";
}
}

if ([top conformsToProtocol:@protocol(SEGScreenReporting)] && [top respondsToSelector:@selector(seg_trackScreen:name:)]) {
__auto_type screenReporting = (UIViewController<SEGScreenReporting>*)top;
[screenReporting seg_trackScreen:top name:name];
return;
}

[[SEGAnalytics sharedAnalytics] screen:name properties:nil options:nil];

[self seg_viewDidAppear:animated];
Expand Down
4 changes: 4 additions & 0 deletions Analytics/Classes/SEGAnalytics.m
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,12 @@ - (void)_applicationWillEnterForeground
if (!self.configuration.trackApplicationLifecycleEvents) {
return;
}
NSString *currentVersion = [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"];
NSString *currentBuild = [[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"];
[self track:@"Application Opened" properties:@{
@"from_background" : @YES,
@"version" : currentVersion ?: @"",
@"build" : currentBuild ?: @"",
}];
}

Expand Down
5 changes: 1 addition & 4 deletions Analytics/Classes/SEGAnalyticsConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,7 @@ - (instancetype)init
_factories = [NSMutableArray array];
Class applicationClass = NSClassFromString(@"UIApplication");
if (applicationClass) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
_application = [applicationClass performSelector:NSSelectorFromString(@"sharedApplication")];
#pragma clang diagnostic pop
_application = [applicationClass performSelector:@selector(sharedApplication)];
}
}
return self;
Expand Down
3 changes: 3 additions & 0 deletions AnalyticsTests/AnalyticsTests-Bridging-Header.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
#import <Analytics/SEGAnalyticsUtils.h>
#import <Analytics/SEGIntegrationsManager.h>
#import <Analytics/SEGUtils.h>
#import <Analytics/SEGScreenReporting.h>

#import "NSData+SEGGUNZIPP.h"
// Temp hack. We should fix the LSNocilla podspec to make this header publicly available
#import "LSMatcher.h"

#import "UIViewController+SegScreenTest.h"
Loading

0 comments on commit ff5d309

Please sign in to comment.