diff --git a/Classes/BITTelemetryContext.h b/Classes/BITTelemetryContext.h new file mode 100644 index 0000000000..31b2450ea1 --- /dev/null +++ b/Classes/BITTelemetryContext.h @@ -0,0 +1,213 @@ +#import +#import "HockeySDK.h" + +#if HOCKEYSDK_FEATURE_TELEMETRY + +#import "HockeySDKPrivate.h" +#import "BITApplication.h" +#import "BITDevice.h" +#import "BITOperation.h" +#import "BITInternal.h" +#import "BITUser.h" +#import "BITSession.h" +#import "BITLocation.h" + +@class BITPersistence; + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const kBITApplicationWasLaunched; +/** + * Context object which contains information about the device, user, session etc. + */ +@interface BITTelemetryContext : NSObject + +/** + * A Dictionary which holds content of property list in memory. + */ +@property (nonatomic, strong) NSMutableDictionary *metaData; + +/** + * The instrumentation key of the app. + */ +@property(nonatomic, strong) BITPersistence *persistence; + +/** + * The instrumentation key of the app. + */ +@property(nonatomic, copy) NSString *instrumentationKey; + +///----------------------------------------------------------------------------- +/// @name Initialisation +///----------------------------------------------------------------------------- + +/** + * A queue which makes array operations thread safe. + */ +@property (nonatomic, strong) dispatch_queue_t operationsQueue; + +/** + * The application context. + */ +@property(nonatomic, strong, readonly) BITApplication *application; + +/** + * The device context. + */ +@property (nonatomic, strong, readonly)BITDevice *device; + +/** + * The location context. + */ +@property (nonatomic, strong, readonly)BITLocation *location; + +/** + * The session context. + */ +@property (nonatomic, strong, readonly)BITSession *session; + +/** + * The user context. + */ +@property (nonatomic, strong, readonly)BITUser *user; + +/** + * The internal context. + */ +@property (nonatomic, strong, readonly)BITInternal *internal; + +/** + * The operation context. + */ +@property (nonatomic, strong, readonly)BITOperation *operation; + +/** + * Initializes a telemetry context. + * + * @param instrumentationKey the instrumentation key of the app. + * @param persistence the persistence used to save and load metadata + * + * @return the telemetry context + */ +- (instancetype)initWithInstrumentationKey:(NSString *)instrumentationKey persistence:(BITPersistence *)persistence; + +///----------------------------------------------------------------------------- +/// @name Users +///----------------------------------------------------------------------------- + +/** + * Use this method to configure the current context. + * + * @param telemetryContextConfigurationBlock block gets the current context as an input. + * Within the block you can update the context object's values to up-to-date. + */ +- (void)setTelemetryContextWithConfigurationBlock:(void (^)(BITTelemetryContext *telemetryContext))telemetryContextConfigurationBlock; + +/** + * Use this method to configure the current user's context. + * + * @param userConfigurationBlock This block gets the current user as an input. + * Within the block you can update the user object's values to up-to-date. + */ +- (void)setUserWithConfigurationBlock:(void (^)(BITUser *user))userConfigurationBlock; + +///----------------------------------------------------------------------------- +/// @name Network status +///----------------------------------------------------------------------------- + +/** + * Get current network type and register for updates. + */ +- (void)configureNetworkStatusTracking; + +///----------------------------------------------------------------------------- +/// @name Helper +///----------------------------------------------------------------------------- + +/** + * Returns context objects as dictionary. + * + * @return a dictionary containing all context fields + */ +- (BITOrderedDictionary *)contextDictionary; + +///----------------------------------------------------------------------------- +/// @name Getter/Setter +///----------------------------------------------------------------------------- + +- (NSString *)screenResolution; + +- (void)setScreenResolution:(NSString *)screenResolution; + +- (NSString *)appVersion; + +- (void)setAppVersion:(NSString *)appVersion; + +- (NSString *)userId; + +- (void)setUserId:(NSString *)userId; + +- (NSString *)userAcquisitionDate; + +- (void)setUserAcquisitionDate:(NSString *)userAcqusitionDate; + +- (NSString *)accountId; + +- (void)setAccountId:(NSString *)accountId; + +- (NSString *)authenticatedUserId; + +- (void)setAuthenticatedUserId:(NSString *)authenticatedUserId; + +- (NSString *)authenticatedUserAcquisitionDate; + +- (void)setAuthenticatedUserAcquisitionDate:(NSString *)authenticatedUserAcquisitionDate; + +- (NSString *)anonymousUserAquisitionDate; + +- (void)setAnonymousUserAquisitionDate:(NSString *)anonymousUserAquisitionDate; + +- (NSString *)sdkVersion; + +- (void)setSdkVersion:(NSString *)sdkVersion; + +- (NSString *)sessionId; + +- (void)setSessionId:(NSString *)sessionId; + +- (NSString *)osVersion; + +- (void)setOsVersion:(NSString *)osVersion; + +- (NSString *)osName; + +- (void)setOsName:(NSString *)osName; + +- (NSString *)deviceModel; + +- (void)setDeviceModel:(NSString *)deviceModel; + +- (NSString *)deviceOemName; + +- (void)setDeviceOemName:(NSString *)oemName; + +- (NSString *)osLocale; + +- (void)setOsLocale:(NSString *)osLocale; + +- (NSString *)deviceId; + +- (void)setDeviceId:(NSString *)deviceId; + +- (NSString *)deviceType; + +- (void)setDeviceType:(NSString *)deviceType; + +- (NSString *)networkType; + +- (void)setNetworkType:(NSString *)networkType; + +@end +NS_ASSUME_NONNULL_END + +#endif /* HOCKEYSDK_FEATURE_TELEMETRY */ diff --git a/Classes/BITTelemetryContext.m b/Classes/BITTelemetryContext.m new file mode 100644 index 0000000000..f66a60d6ec --- /dev/null +++ b/Classes/BITTelemetryContext.m @@ -0,0 +1,466 @@ +#import +#import "BITTelemetryContext.h" + +#if HOCKEYSDK_FEATURE_TELEMETRY + +#import "BITTelemetryManagerPrivate.h" +#import "BITHockeyHelper.h" +#import "BITReachability.h" +#import "BITOrderedDictionary.h" +#import "BITPersistence.h" + +NSString *const kBITTelemetrySessionId = @"BITTelemetrySessionId"; +NSString *const kBITSessionAcquisitionTime = @"BITSessionAcquisitionTime"; + +static char *const BITContextOperationsQueue = "net.hockeyapp.telemetryContextQueue"; + +@implementation BITTelemetryContext + +@synthesize instrumentationKey = _instrumentationKey; +@synthesize persistence = _persistence; + +#pragma mark - Initialisation + +-(instancetype)init { + + if(self = [super init]) { + _operationsQueue = dispatch_queue_create(BITContextOperationsQueue, DISPATCH_QUEUE_CONCURRENT); + } + return self; +} + +- (instancetype)initWithInstrumentationKey:(NSString *)instrumentationKey persistence:(BITPersistence *)persistence { + + if ((self = [self init])) { + _persistence = persistence; + _instrumentationKey = instrumentationKey; + BITDevice *deviceContext = [BITDevice new]; + deviceContext.model = bit_devicePlatform(); + deviceContext.type = bit_deviceType(); + deviceContext.osVersion = bit_osVersionBuild(); + deviceContext.os = bit_osName(); + deviceContext.deviceId = bit_appAnonID(NO); + deviceContext.locale = bit_deviceLocale(); + deviceContext.language = bit_deviceLanguage(); + deviceContext.screenResolution = bit_screenSize(); + deviceContext.oemName = @"Apple"; + + BITInternal *internalContext = [BITInternal new]; + internalContext.sdkVersion = bit_sdkVersion(); + + BITApplication *applicationContext = [BITApplication new]; + applicationContext.version = bit_appVersion(); + + BITOperation *operationContext = [BITOperation new]; + + NSMutableDictionary *restoredMetaData = [[_persistence metaData] mutableCopy]; + _metaData = restoredMetaData ?: @{}.mutableCopy; + _metaData[@"users"] = restoredMetaData[@"users"] ?: @{}.mutableCopy; + + BITUser *userContext = [self userForDate:[NSDate date]]; + if (!userContext) { + userContext = [self newUser]; + [self addUser:userContext forDate:[NSDate date]]; + } + + BITLocation *locationContext = [BITLocation new]; + BITSession *sessionContext = [BITSession new]; + + _application = applicationContext; + _device = deviceContext; + _location = locationContext; + _user = userContext; + _internal = internalContext; + _operation = operationContext; + _session = sessionContext; + + [self configureNetworkStatusTracking]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - User + +- (BITUser *)newUser { + return ({ + BITUser *user = [BITUser new]; + user.userId = bit_appAnonID(NO); + user; + }); +} + +- (void)addUser:(BITUser *)user forDate:(NSDate *)date { + NSString *timestamp = [self unixTimestampFromDate:date ?: [NSDate date]]; + + __weak typeof(self) weakSelf = self; + dispatch_sync(self.operationsQueue, ^{ + typeof(self) strongSelf = weakSelf; + NSMutableDictionary *users = strongSelf.metaData[@"users"]; + users[timestamp] = user; + [self.persistence persistMetaData:strongSelf.metaData]; + }); +} + +- (BITUser *)userForDate:(NSDate *)date { + NSString *timestamp = [self unixTimestampFromDate:date]; + NSMutableDictionary *users = self.metaData[@"users"]; + + __block BITUser *user = nil; + + __weak typeof(self) weakSelf = self; + dispatch_sync(self.operationsQueue, ^{ + typeof(self) strongSelf = weakSelf; + + NSString *userKey = [strongSelf keyForTimestamp:timestamp inDictionary:users]; + user = users[userKey]; + }); + + return user; +} + +- (NSString *)unixTimestampFromDate:(NSDate *)date { + return [NSString stringWithFormat:@"%ld", (time_t) [date timeIntervalSince1970]]; +} + +- (NSString *)keyForTimestamp:(NSString *)timestamp inDictionary:(NSDictionary *)dict { + for(NSString *key in [self sortedKeysOfDictionay:dict]) { + if([timestamp doubleValue] >= [key doubleValue]) { + return key; + } + } + return nil; +} + +- (NSArray *)sortedKeysOfDictionay:(NSDictionary *)dict { + NSMutableArray *keys = [[dict allKeys] mutableCopy]; + NSArray *sortedArray = [keys sortedArrayUsingComparator:^(id a, id b) { + return [b compare:a options:NSNumericSearch]; + }]; + return sortedArray; +} + +#pragma mark - Network + +- (void)configureNetworkStatusTracking { + [[BITReachability sharedInstance] startNetworkStatusTracking]; + _device.network = [[BITReachability sharedInstance] descriptionForActiveReachabilityType]; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserver:self selector:@selector(updateNetworkType:) name:kBITReachabilityTypeChangedNotification object:nil]; +} + +- (void)updateNetworkType:(NSNotification *)notification { + [self setNetworkType:[notification userInfo][kBITReachabilityUserInfoName]]; +} + +#pragma mark - Getter/Setter properties + +- (NSString *)instrumentationKey { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _instrumentationKey; + }); + return tmp; +} + +- (void)setInstrumentationKey:(NSString *)instrumentationKey { + NSString* tmp = [instrumentationKey copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _instrumentationKey = tmp; + }); +} + +- (NSString *)screenResolution { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _device.screenResolution; + }); + return tmp; +} + +- (void)setScreenResolution:(NSString *)screenResolution { + NSString* tmp = [screenResolution copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _device.screenResolution = tmp; + }); +} + +- (NSString *)appVersion { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _application.version; + }); + return tmp; +} + +- (void)setAppVersion:(NSString *)appVersion { + NSString* tmp = [appVersion copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _application.version = tmp; + }); +} + +- (NSString *)userId { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _user.userId; + }); + return tmp; +} + +- (void)setUserId:(NSString *)userId { + NSString* tmp = [userId copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _user.userId = tmp; + }); +} + +- (NSString *)userAcquisitionDate { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _user.accountAcquisitionDate; + }); + return tmp; +} + +- (void)setUserAcquisitionDate:(NSString *)userAcqusitionDate { + NSString* tmp = [userAcqusitionDate copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _user.accountAcquisitionDate = tmp; + }); +} + +- (NSString *)accountId { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _user.accountId; + }); + return tmp; +} + +- (void)setAccountId:(NSString *)accountId { + NSString* tmp = [accountId copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _user.accountId = tmp; + }); +} + +- (NSString *)authenticatedUserId { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _user.authUserId; + }); + return tmp; +} + +- (void)setAuthenticatedUserId:(NSString *)authenticatedUserId { + NSString* tmp = [authenticatedUserId copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _user.authUserId = tmp; + }); +} + +- (NSString *)authenticatedUserAcquisitionDate { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _user.authUserAcquisitionDate; + }); + return tmp; +} + +- (void)setAuthenticatedUserAcquisitionDate:(NSString *)authenticatedUserAcquisitionDate { + NSString* tmp = [authenticatedUserAcquisitionDate copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _user.authUserAcquisitionDate = tmp; + }); +} + +- (NSString *)anonymousUserAquisitionDate { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _user.anonUserAcquisitionDate; + }); + return tmp; +} + +- (void)setAnonymousUserAquisitionDate:(NSString *)anonymousUserAquisitionDate { + NSString* tmp = [anonymousUserAquisitionDate copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _user.anonUserAcquisitionDate = tmp; + }); +} + +- (NSString *)sdkVersion { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _internal.sdkVersion; + }); + return tmp; +} + +- (void)setSdkVersion:(NSString *)sdkVersion { + NSString* tmp = [sdkVersion copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _internal.sdkVersion = tmp; + }); +} + +- (NSString *)sessionId { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _session.sessionId; + }); + return tmp; +} + +- (void)setSessionId:(NSString *)sessionId { + NSString* tmp = [sessionId copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _session.sessionId = tmp; + }); +} + +- (NSString *)osVersion { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _device.osVersion; + }); + return tmp; +} + +- (void)setOsVersion:(NSString *)osVersion { + NSString* tmp = [osVersion copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _device.osVersion = tmp; + }); +} + +- (NSString *)osName { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _device.os; + }); + return tmp; +} + +- (void)setOsName:(NSString *)osName { + NSString* tmp = [osName copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _device.os = tmp; + }); +} + +- (NSString *)deviceModel { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _device.model; + }); + return tmp; +} + +- (void)setDeviceModel:(NSString *)deviceModel { + NSString* tmp = [deviceModel copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _device.model = tmp; + }); +} + +- (NSString *)deviceOemName { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _device.oemName; + }); + return tmp; +} + +- (void)setDeviceOemName:(NSString *)oemName { + NSString* tmp = [oemName copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _device.oemName = tmp; + }); +} + +- (NSString *)osLocale { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _device.locale; + }); + return tmp; +} + +- (void)setOsLocale:(NSString *)osLocale { + NSString* tmp = [osLocale copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _device.locale = tmp; + }); +} + +- (NSString *)deviceId { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _device.deviceId; + }); + return tmp; +} + +- (void)setDeviceId:(NSString *)deviceId { + NSString* tmp = [deviceId copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _device.deviceId = tmp; + }); +} + +- (NSString *)deviceType { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _device.type; + }); + return tmp; +} + +- (void)setDeviceType:(NSString *)deviceType { + NSString* tmp = [deviceType copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _device.type = tmp; + }); +} + +- (NSString *)networkType { + __block NSString *tmp; + dispatch_sync(_operationsQueue, ^{ + tmp = _device.network; + }); + return tmp; +} + +- (void)setNetworkType:(NSString *)networkType { + NSString* tmp = [networkType copy]; + dispatch_barrier_async(_operationsQueue, ^{ + _device.network = tmp; + }); +} + +#pragma mark - Custom getter +#pragma mark - Helper + +// TODO: Cache context +- (BITOrderedDictionary *)contextDictionary { + __block BITOrderedDictionary *contextDictionary = [BITOrderedDictionary new]; + dispatch_sync(_operationsQueue, ^{ + [contextDictionary addEntriesFromDictionary:[self.session serializeToDictionary]]; + [contextDictionary addEntriesFromDictionary:[self.user serializeToDictionary]]; + [contextDictionary addEntriesFromDictionary:[self.device serializeToDictionary]]; + [contextDictionary addEntriesFromDictionary:[self.application serializeToDictionary]]; + [contextDictionary addEntriesFromDictionary:[self.location serializeToDictionary]]; + [contextDictionary addEntriesFromDictionary:[self.internal serializeToDictionary]]; + [contextDictionary addEntriesFromDictionary:[self.operation serializeToDictionary]]; + }); + return contextDictionary; +} + +@end + +#endif /* HOCKEYSDK_FEATURE_TELEMETRY */ diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 37f2f0fa21..7a1d93c264 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -45,6 +45,10 @@ 1B330A621B98E13C007844AB /* BITDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B330A5F1B98E13C007844AB /* BITDevice.h */; }; 1B330A631B98E13C007844AB /* BITDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B330A601B98E13C007844AB /* BITDevice.m */; }; 1B330A641B98E13C007844AB /* BITDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B330A601B98E13C007844AB /* BITDevice.m */; }; + 1B330A711B98E267007844AB /* BITTelemetryContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B330A6E1B98E267007844AB /* BITTelemetryContext.h */; }; + 1B330A721B98E267007844AB /* BITTelemetryContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B330A6E1B98E267007844AB /* BITTelemetryContext.h */; }; + 1B330A731B98E267007844AB /* BITTelemetryContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B330A6F1B98E267007844AB /* BITTelemetryContext.m */; }; + 1B330A741B98E267007844AB /* BITTelemetryContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B330A6F1B98E267007844AB /* BITTelemetryContext.m */; }; 1B330A791B98E64A007844AB /* BITApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B330A771B98E64A007844AB /* BITApplication.h */; }; 1B330A7A1B98E64A007844AB /* BITApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B330A771B98E64A007844AB /* BITApplication.h */; }; 1B330A7B1B98E64A007844AB /* BITApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B330A781B98E64A007844AB /* BITApplication.m */; }; @@ -463,6 +467,8 @@ 1B330A5A1B98DFC7007844AB /* BITData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITData.m; sourceTree = ""; }; 1B330A5F1B98E13C007844AB /* BITDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITDevice.h; sourceTree = ""; }; 1B330A601B98E13C007844AB /* BITDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITDevice.m; sourceTree = ""; }; + 1B330A6E1B98E267007844AB /* BITTelemetryContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITTelemetryContext.h; sourceTree = ""; }; + 1B330A6F1B98E267007844AB /* BITTelemetryContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITTelemetryContext.m; sourceTree = ""; }; 1B330A771B98E64A007844AB /* BITApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITApplication.h; sourceTree = ""; }; 1B330A781B98E64A007844AB /* BITApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITApplication.m; sourceTree = ""; }; 1B330A7D1B98E6A2007844AB /* BITOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITOperation.h; sourceTree = ""; }; @@ -798,6 +804,10 @@ 1B87EFB31B8D0C540007C96B /* BITTelemetryManager.h */, 1B87EFB41B8D0C540007C96B /* BITTelemetryManager.m */, 1B87EFB71B8D0F800007C96B /* BITTelemetryManagerPrivate.h */, + 1B98D4571B98F6CA00B8000B /* BITReachability.h */, + 1B98D4581B98F6CA00B8000B /* BITReachability.m */, + 1B330A6E1B98E267007844AB /* BITTelemetryContext.h */, + 1B330A6F1B98E267007844AB /* BITTelemetryContext.m */, 1BD33EAD1B950DC700C3368B /* BITChannel.h */, 1BD33EAE1B950DC700C3368B /* BITChannel.m */, B27FBEFB1B9622700082406A /* BITPersistence.h */, @@ -1247,6 +1257,7 @@ 1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */, E48A3DEC17B3ED1C00924C3D /* BITAuthenticator.h in Headers */, 1E754E5C1621FBB70070AB92 /* BITCrashManager.h in Headers */, + 1B330A711B98E267007844AB /* BITTelemetryContext.h in Headers */, 1B6852E01B95361D00D5C387 /* BITSessionStateData.h in Headers */, 1E754E5E1621FBB70070AB92 /* BITCrashManagerDelegate.h in Headers */, 1B6852C81B952BE900D5C387 /* BITBase.h in Headers */, @@ -1326,6 +1337,7 @@ 1EB6176D1B0A30CC0035A986 /* BITWebTableViewCell.h in Headers */, 1EB617AF1B0A31CA0035A986 /* HockeySDKFeatureConfig.h in Headers */, 1EB6177A1B0A310F0035A986 /* BITCrashDetailsPrivate.h in Headers */, + 1B330A721B98E267007844AB /* BITTelemetryContext.h in Headers */, 1B6852E11B95361D00D5C387 /* BITSessionStateData.h in Headers */, 1EB6179D1B0A31760035A986 /* BITFeedbackListViewController.h in Headers */, 1B6852C91B952BE900D5C387 /* BITBase.h in Headers */, @@ -1722,6 +1734,7 @@ 1E49A4BB161222B900463151 /* BITHockeyBaseViewController.m in Sources */, 97F0FA0518B2294D00EF50AA /* BITFeedbackMessageAttachment.m in Sources */, 1E49A4C7161222B900463151 /* BITAppStoreHeader.m in Sources */, + 1B330A731B98E267007844AB /* BITTelemetryContext.m in Sources */, 1B6852CA1B952BE900D5C387 /* BITBase.m in Sources */, 1E49A4CD161222B900463151 /* BITStoreButton.m in Sources */, 1E90FD7418EDB86400CF0417 /* BITCrashDetails.m in Sources */, @@ -1814,6 +1827,7 @@ 1EB6178F1B0A31510035A986 /* BITFeedbackManager.m in Sources */, 1EB6178B1B0A31510035A986 /* BITFeedbackUserDataViewController.m in Sources */, 1EB617931B0A31510035A986 /* BITUpdateViewController.m in Sources */, + 1B330A741B98E267007844AB /* BITTelemetryContext.m in Sources */, 1B6852CB1B952BE900D5C387 /* BITBase.m in Sources */, 1EB617901B0A31510035A986 /* BITActivityIndicatorButton.m in Sources */, 1EB6178E1B0A31510035A986 /* BITFeedbackActivity.m in Sources */,